一旦 数据模型 创建完毕, 自然会有存取数据的需要.本文档介绍了由 models 衍生而来的数据库抽象API,及如何创建,得到及更新对象.
贯穿本参考, 我们都会引用下面的民意测验(Poll)应用程序:
class Poll(models.Model): slug = models.SlugField(unique_for_month=‘pub_date‘) question = models.CharField(maxlength=255) pub_date = models.DateTimeField() expire_date = models.DateTimeField() def __repr__(self): return self.question class Meta: get_latest_by = ‘pub_date‘ class Choice(models.Model): poll = models.ForeignKey(Poll, edit_inline=models.TABULAR, num_in_admin=10, min_num_in_admin=5) choice = models.CharField(maxlength=255, core=True) votes = models.IntegerField(editable=False, default=0) def __repr__(self): return self.choice及下面的简单会话:
>>> from datetime import datetime >>> p1 = Poll(slug=‘whatsup‘, question="What‘s up?", ... pub_date=datetime(2005, 2, 20), expire_date=datetime(2005, 4, 20)) >>> p1.save() >>> p2 = Poll(slug=‘name‘, question="What‘s your name?", ... pub_date=datetime(2005, 3, 20), expire_date=datetime(2005, 3, 25)) >>> p2.save() >>> Poll.objects.all() [What‘s up?, What‘s your name?]查询如何运作
Django 的数据查询基于构建结果集及对结果集进行取值. 结果集是独立于数据库的符合某个查询条件的一组数据对象的集合.这是一个惰性集合:在对该集合取值之前,无法知道该集合有哪些成员.
要生成一个满足你需求的结果集,首先要得到一个描述给定类型的所有对象的初始结果集.这个初始结果集可以通过一系列函数进行更精细的优化处理.当经过处理后的结果集符合你的要求时, 就可以对它进行取值操作(使用迭代操作,slicing操作,或一系列其它技术), 以得到一个你需要的对象或对象的列表.
获得初始结果集
每个 Django model 都有一个与生俱来的管理器对象 objects, 管理器最重要的角色就是作为初始结果的来源. 一个管理器就是一个描述给定类型所有对象的特殊的初始结果集. Poll.objects 就是包含所有 Poll 对象的一个初始结果集. 它唯一特殊之处在于它不能被取值. 要克服此限制, 管理器对象有一个 all() 方法. 该方法生成一个 可以 被取值的初始结果集的拷贝:
all_polls = Poll.objects.all()参阅 Model API 的 小节以了解管理器的定位及创建细节.
优化定制结果集
管理器提供的初始结果集描述了给定类型的所有对象.不过通常你只需要这个对象集合中的一小部分(一个子集).
要生这样一个结果集,你需要对初始结果集进行优化定制处理, 增加一些限制条件直到描述的子集满足你的需要.最常用的两个定制结果集的方法是:
filter(**kwargs) 返回一个匹配查询参数的新的结果集. exclude(**kwargs) 返回一个不匹配查询参数的新的结果集.参数格式在下面 "字段查询" 小节有描述.
这两个方法的返回值都是结果集对象,因此结果集可以进行链式处理:
Poll.objects.filter( question__startswith="What").exclude( pub_date__gte=datetime.now()).filter( pub_date__gte=datetime(2005,1,1))...以一个初始结果集作为参数, 然后进行过滤, 再进行排除, 再进行另一个过滤. 这样得到的最终结果就一个问题开头单词是 "What", 发布日期在 2005年1月1日至今的所有民意测验的集合.
每个结果集都是一个独一无二的对象. 以上操作的每一步都生成了一个新的结果集:
q1 = Poll.objects.filter(question__startswith="What") q2 = q1.exclude(pub_date__gte=datetime.now()) q3 = q1.filter(pub_date__gte=datetime.now())这三步生成了三个结果集; 一个初始结果集包含所有的以"What"开头的民意测验, 两个初始结果集的子集(一个排除条件,一个过滤条件).对原始结果集的改进过程并没有影响到原始的结果集.
值得注意的是结果集的创建根本没有访问数据库.只有当对结果集取值时才会访问数据库.
字段查询
以 field__lookuptype (注意是双下线)形式进行基本的字段查询,举例来说:
polls.objects.filter(pub_date__lte=datetime.now())该查询翻译成SQL就是:
SELECT * FROM polls_polls WHERE pub_date <= NOW();
实现细节
Python 能够在定义函数时接受任意的 name-value(names和values均可以在运行时通过计算得到)参数. 要了解更多信息,参阅官方 Python 教程中的 .
DB API 支持下列查找类型:
类型描述exact 精确匹配: polls.get_object(id__exact=14).
iexact 忽略大小写的精确匹配: polls.objects.filter(slug__iexact="foo") 匹配 foo, FOO, fOo, 等等.
contains 大小写敏感的内容包含测试: polls.objects.filter(question__contains="spam") 返回question 中包含 "spam" 的所有民意测验.(仅PostgreSQL 和 MySQL支持. SQLite 的LIKE 语句不支持大小写敏感特性. 对Sqlite 来说, contains 等于 icontains.)
icontains 大小写不敏感的内容包含测试:
gt 大于: polls.objects.filter(id__gt=4).
gte 大于等于.
lt 小于.
lte 小于等于.
ne 不等于.
in 位于给定列表中: polls.objects.filter(id__in=[1, 3, 4]) 返回一个 polls 列表(ID 值分别是 1或3或4).
startswith 大小写敏感的 starts-with: polls.objects.filter(question__startswith="Would").(仅PostgreSQL 和MySQL支持. SQLite 的LIKE 语句不支持大小写敏感特性. 对Sqlite 来说,``startswith`` 等于 istartswith)
endswith 大小写敏感的 ends-with. (仅PostgreSQL 和 MySQL)
istartswith 大小写不敏感的 starts-with.
iendswith 大小写不敏感的 ends-with.
range 范围测试: polls.objects.filter(pub_date__range=(start_date, end_date)) 返回 pub_date 位于 start_date 和 end_date (包括)之间的所有民意测验
year 对 date/datetime 字段, 进行精确的 年 匹配: polls.get_count(pub_date__year=2005).
month 对 date/datetime 字段, 进行精确的 月 匹配:
day 对 date/datetime 字段, 进行精确的 日 匹配:
isnull True/False; 做 IF NULL/IF NOT NULL 查询: polls.objects.filter(expire_date__isnull=True).
如果未提供查找类型, 系统就认为查找类型是 exact . 下面两个语句是等价的:
Poll.objects.get(id=14) Poll.objects.get(id__exact=14)查询允许多个条件参数, 逗号分隔的多个条件参数会被 "AND" 起来使用:
polls.objects.filter( pub_date__year=2005, pub_date__month=1, question__startswith="Would", )...得到2005年1月公布的带有一个"Would"开头的问题的所有民意测验.