话说上次说到数据库的基本访问,而数据库我们主要进行的操作就是CRUD,也即是做计算处理时的增加(Create)、读取(Retrieve)(重新得到数据)、更新(Update)和删除(Delete),俗称:增删改查。废话不多说,学习开始。

  插入和更新数据

  你已经知道怎么做了: 先使用一些关键参数创建对象实例,如下:

  1. >>> p = Publisher(name='Apress',
  2. ... address='2855 Telegraph Ave.',
  3. ... city='Berkeley',
  4. ... state_province='CA',
  5. ... country='U.S.A.',
  6. ... website='http://www.apress.com/')

  这个对象实例并 没有 对数据库做修改。 在调用`` save()`` 方法之前,记录并没有保存至数据库,像这样:  

  1. >>> p.save()

  在SQL里,这大致可以转换成这样:

  1. INSERT INTO books_publisher
  2. (name, address, city, state_province, country, website)
  3. VALUES
  4. ('Apress', '2855 Telegraph Ave.', 'Berkeley', 'CA',
  5. 'U.S.A.', 'http://www.apress.com/');

  因为 Publisher 模型有一个自动增加的主键 id ,所以第一次调用 save() 还多做了一件事: 计算这个主键的值并把它赋值给这个对象实例: 

  1. >>> p.id
  2. 3L # this will differ based on your own data

  接下来再调用 save() 将不会创建新的记录,而只是修改记录内容(也就是 执行 UPDATE SQL语句,而不是INSERT 语句):

  1. >>> p.name = 'Apress Publishing'
  2. >>> p.save()

  前面执行的 save() 相当于下面的SQL语句:  

  1. UPDATE books_publisher SET
  2. name = 'Apress Publishing',
  3. address = '2855 Telegraph Ave.',
  4. city = 'Berkeley',
  5. state_province = 'CA',
  6. country = 'U.S.A.',
  7. website = 'http://www.apress.com'
  8. WHERE id = 3L;

  注意,并不是只更新修改过的那个字段,所有的字段都会被更新。 这个操作有可能引起竞态条件,这取决于你的应用程序。

  选择对象

  当然,创建新的数据库,并更新之中的数据是必要的,但是,对于 Web 应用程序来说,更多的时候是在检索查询数据库。 我们已经知道如何从一个给定的模型中取出所有记录:

  1. >>> Publisher.objects.all()
  2. [<Publisher: Apress>, <Publisher: O'Reilly>]

  这相当于这个SQL语句:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher;

  注意到Django在选择所有数据时并没有使用 SELECT* ,而是显式列出了所有字段。 设计的时候就是这样:SELECT* 会更慢,而且最重要的是列出所有字段遵循了Python 界的一个信条: 明言胜于暗示。

  有关Python之禅(戒律) :-),在Python提示行输入 import this 试试看。

  让我们来仔细看看 Publisher.objects.all() 这行的每个部分:

  • 首先,我们有一个已定义的模型 Publisher 。没什么好奇怪的: 你想要查找数据, 你就用模型来获得数据。
  • 然后,是objects属性。 它被称为管理器,我们将在第10章中详细讨论它。 目前,我们只需了解管理器管理着所有针对数据包含、还有最重要的数据查询的表格级操作。
  • 所有的模型都自动拥有一个 objects 管理器;你可以在想要查找数据时使用它。
  • 最后,还有 all() 方法。这个方法返回返回数据库中所有的记录。 尽管这个对象 看起来 象一个列表(list),它实际是一个 QuerySet 对象, 这个对象是数据库中一些记录的集合。 附录C将详细描述QuerySet。 现在,我们就先当它是一个仿真列表对象好了。

  任何对数据库的查询操作都遵循这样的模式:即 调用绑定在该模型上的管理器(objects)的相应方法(如all)。

  数据过滤

  我们很少会一次性从数据库中取出所有的数据;通常都只针对一部分数据进行操作。 在Django API中,我们可以使用 “filter()” 方法对数据进行过滤: 

  1. >>> Publisher.objects.filter(name='Apress')
  2. [<Publisher: Apress>]

  filter() 根据关键字参数来转换成 WHERE SQL语句。 前面这个例子 相当于这样:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. WHERE name = 'Apress';

  你可以传递多个参数到 filter() 来缩小选取范围:

  1. >>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
  2. [<Publisher: Apress>]

  多个参数会被转换成 AND SQL从句, 因此上面的代码可以转化成这样:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. WHERE country = 'U.S.A.'
  4. AND state_province = 'CA';

 注意,SQL缺省的 = 操作符是精确匹配的, 其他类型的查找也可以使用:

  1. >>> Publisher.objects.filter(name__contains="press")
  2. [<Publisher: Apress>]

  在 name 和 contains 之间有双下划线。和Python一样,Django也使用双下划线来表明会进行一些魔术般的操作。这里,contains部分会被Django翻译成LIKE语句: 

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. WHERE name LIKE '%press%';

  其他的一些查找类型有:icontains(大小写无关的LIKE),startswithendswith, 还有range(SQLBETWEEN查询)。

  获取单个对象

  上面的例子中“ filter()” 函数返回一个记录集,这个记录集是一个列表。 相对列表来说,有些时候我们更需要获取单个的对象, “get()” 方法就是在此时使用的:

  1. >>> Publisher.objects.get(name="Apress")
  2. <Publisher: Apress>

  这样,就返回了单个对象,而不是列表(更准确的说,QuerySet)。 所以,如果结果是多个对象,会导致抛出异常: 

  1. >>> Publisher.objects.get(country="U.S.A.")
  2. Traceback (most recent call last):
  3. ...
  4. MultipleObjectsReturned: get() returned more than one Publisher --
  5. it returned 2! Lookup parameters were {'country': 'U.S.A.'}

  如果查询没有返回结果也会抛出异常:

  1. >>> Publisher.objects.get(name="Penguin")
  2. Traceback (most recent call last):
  3. ...
  4. DoesNotExist: Publisher matching query does not exist.

  这个 DoesNotExist 异常 是 Publisher 这个 model 类的一个属性,即 Publisher.DoesNotExist。在你的应用中,你可以捕获并处理这个异常,像这样: 

  1. try:
  2. p = Publisher.objects.get(name='Apress')
  3. except Publisher.DoesNotExist:
  4. print "Apress isn't in the database yet."
  5. else:
  6. print "Apress is in the database."

  数据排序

  在运行前面的例子中,你可能已经注意到返回的结果是无序的。 我们还没有告诉数据库 怎样对结果进行排序,所以我们返回的结果是无序的。

  在你的 Django 应用中,你或许希望根据某字段的值对检索结果排序,比如说,按字母顺序。 那么,使用order_by() 这个方法就可以搞定了。

  1. >>> Publisher.objects.order_by("name")
  2. [<Publisher: Apress>, <Publisher: O'Reilly>]

  跟以前的 all() 例子差不多,SQL语句里多了指定排序的部分: 

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. ORDER BY name;

  如果需要以多个字段为标准进行排序(第二个字段会在第一个字段的值相同的情况下被使用到),使用多个参数就可以了,如下:

  1. >>> Publisher.objects.order_by("state_province", "address")
  2. [<Publisher: Apress>, <Publisher: O'Reilly>]

  我们还可以指定逆向排序,在前面加一个减号 - 前缀:

  1. >>> Publisher.objects.order_by("-name")
  2. [<Publisher: O'Reilly>, <Publisher: Apress>]

  尽管很灵活,但是每次都要用 order_by() 显得有点啰嗦。 大多数时间你通常只会对某些 字段进行排序。 在这种情况下,Django让你可以指定模型的缺省排序方式:

  1. class Publisher(models.Model):
  2. name = models.CharField(max_length=30)
  3. address = models.CharField(max_length=50)
  4. city = models.CharField(max_length=60)
  5. state_province = models.CharField(max_length=30)
  6. country = models.CharField(max_length=50)
  7. website = models.URLField()
  8.  
  9. def __unicode__(self):
  10. return self.name
  11.  
  12. class Meta:
  13. ordering = ['name']

  现在,让我们来接触一个新的概念。 class Meta,内嵌于 Publisher 这个类的定义中(如果 class Publisher是顶格的,那么 class Meta 在它之下要缩进4个空格--按 Python 的传统 )。你可以在任意一个 模型 类中使用 Meta 类,来设置一些与特定模型相关的选项。 在 附录B 中有 Meta 中所有可选项的完整参考,现在,我们关注 ordering 这个选项就够了。 如果你设置了这个选项,那么除非你检索时特意额外地使用了 order_by(),否则,当你使用 Django 的数据库 API 去检索时,Publisher对象的相关返回值默认地都会按 name 字段排序。

  更新多个对象

  在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。

  例如说我们现在想要将Apress Publisher的名称由原来的”Apress”更改为”Apress Publishing”。若使用save()方法,如:

  1. >>> p = Publisher.objects.get(name='Apress')
  2. >>> p.name = 'Apress Publishing'
  3. >>> p.save()

  这等同于如下SQL语句:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. WHERE name = 'Apress';
  4.  
  5. UPDATE books_publisher SET
  6. name = 'Apress Publishing',
  7. address = '2855 Telegraph Ave.',
  8. city = 'Berkeley',
  9. state_province = 'CA',
  10. country = 'U.S.A.',
  11. website = 'http://www.apress.com'
  12. WHERE id = 3L;

  在这个例子里我们可以看到Django的save()方法更新了不仅仅是name列的值,还有更新了所有的列。 若name以外的列有可能会被其他的进程所改动的情况下,只更改name列显然是更加明智的。 更改某一指定的列,我们可以调用结果集(QuerySet)对象的update()方法: 示例如下:

  1. >>> Publisher.objects.filter(id=52).update(name='Apress Publishing')

  与之等同的SQL语句变得更高效,并且不会引起竞态条件。  

  1. UPDATE books_publisher
  2. SET name = 'Apress Publishing'
  3. WHERE id = 3L;

  update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录。 以下示例演示如何将所有Publisher的country字段值由’U.S.A’更改为’USA’: 

  1. >>> Publisher.objects.all().update(country='USA')
  2. 2

   update()方法会返回一个整型数值,表示受影响的记录条数。 在上面的例子中,这个值是2。

  删除对象

  删除数据库中的对象只需调用该对象的delete()方法即可:

  1. >>> p = Publisher.objects.get(name="O'Reilly")
  2. >>> p.delete()
  3. >>> Publisher.objects.all()
  4. [<Publisher: Apress Publishing>]

  同样我们可以在结果集上调用delete()方法同时删除多条记录。这一点与我们上一小节提到的update()方法相似:

  1. >>> Publisher.objects.filter(country='USA').delete()
  2. >>> Publisher.objects.all().delete()
  3. >>> Publisher.objects.all()
  4. []

  删除数据时要谨慎! 为了预防误删除掉某一个表内的所有数据,Django要求在删除表内所有数据时显示使用all()。 比如,下面的操作将会出错: 

  1. >>> Publisher.objects.delete()
  2. Traceback (most recent call last):
  3. File "<console>", line 1, in <module>
  4. AttributeError: 'Manager' object has no attribute 'delete'

  而一旦使用all()方法,所有数据将会被删除:

  1. >>> Publisher.objects.all().delete()

Python框架之Django学习笔记(十一)的更多相关文章

  1. Python框架之Django学习笔记(十七)

    Django框架之表单(续二) 今天的这篇博客将是Django学习笔记博客的最后一篇,基本每周最少一篇的Django框架学习,坚持到今天也实属不易,当然了,这个框架的学习仅仅是Django框架的基础部 ...

  2. Python框架之Django学习笔记(十二)

    Django站点管理 十一转眼结束,说好的充电没能顺利开展,反而悠闲的看了电视剧以及去影院看了新上映的<心花路放>.<亲爱的>以及<黄金时代>,说好的劳逸结合现在回 ...

  3. Python框架之Django学习笔记(十)

    又是一周周末,如约学习Django框架.在上一次,介绍了MVC开发模式以及Django自己的MVT开发模式,此次,就从数据处理层Model谈起. 数据库配置 首先,我们需要做些初始配置:我们需要告诉D ...

  4. Python框架之Django学习笔记(六)

    模板 上篇博文学习了动态视图,但是,视图中返回文本的方式有点特别. 也就是说,HTML被直接硬编码在 Python 代码之中. def current_datetime(request): now = ...

  5. Python框架之Django学习笔记(十六)

    Django框架之表单(续) 今天简直无力吐槽了,去了香山,结果和网上看到的简直是天壤之别啊,说好的香山的枫树呢?说好的香山的红叶呢?说好的漫山遍野一片红呢?本以为在山上,一口气爬上去,沿路基本都是翠 ...

  6. Python框架之Django学习笔记(十五)

    表单 从Google的简朴的单个搜索框,到常见的Blog评论提交表单,再到复杂的自定义数据输入接口,HTML表单一直是交互性网站的支柱.本次内容将介绍如何用Django对用户通过表单提交的数据进行访问 ...

  7. Python框架之Django学习笔记(九)

    模型 之前,我们用 Django 建造网站的基本途径: 建立视图和 URLConf . 正如我们所阐述的,视图负责处理一些主观逻辑,然后返回响应结果. 作为例子之一,我们的主观逻辑是要计算当前的日期和 ...

  8. Python框架之Django学习笔记(五)

    第一个Django网页小结 进来的请求转入/hello/. Django通过在ROOT_URLCONF配置来决定根URLconf. Django在URLconf中的所有URL模式中,查找第一个匹配/h ...

  9. Python框架之Django学习笔记(一)

    Django历史: Django 是从真实世界的应用中成长起来的,它是由 堪萨斯(Kansas)州 Lawrence 城中的一个 网络开发小组编写的. 它诞生于 2003 年秋天,那时 Lawrenc ...

随机推荐

  1. Bootstrap插件-collapse

    <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title> ...

  2. C# Dictionary的遍历

    foreach (KeyValuePair<string, string> kvp in dic) { Console.WriteLine("key:{0},value:{1}& ...

  3. JAVA和数据库工具的下载地址(备用)

    sqlite数据库驱动下载: http://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/

  4. 【MFC】可以换行的编辑框

    在mfc中编辑框允许输入多行时,换行符被表示为<归位><换行>即“\r\n”,用ascii码表示为13 10 如果为编辑框中想要输入换行,就请将编辑框的属性: Auto HSc ...

  5. MAC MAMP install yaf

    Yaf doesn't support PHP 5.6! You may see this: Warning: PHP Startup: yaf: Unable to initialize modul ...

  6. yii相关手册文档

    1.Yii官方手册 Yii Framework 2.0 权威指南:http://www.yiichina.com/doc/guide/2.0/start-databases 2.yii高级应用程序手册 ...

  7. 论overflow滚动的重要性

    原理 设置一个块级作用域溢出的效果,只需要在外部块的位置上设置overflow:scroll和height:xx即可. 此时,块级作用域的内容位移超出外部块的位移就会出现滚动条,当内部块滚动时,我们能 ...

  8. [Rails学习之路]初识Ruby(二)

    继续上次Ruby的学习.接下来就到了Ruby的方法. Ruby的方法与Python仍然很像.使用def定义,可以使用undef取消定义. 在Ruby中,经常可以看见方法后面跟有"?" ...

  9. hdu-1162 Eddy's picture---浮点数的MST

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1162 题目大意: 给n个点,求MST权值 解题思路: 直接prim算法 #include<bi ...

  10. a low memory warning should only destroy the layer’s bitmap

    https://stablekernel.com/view-controller-in-ios-6/ Some of you may have noticed that your view contr ...