model操作涉及的所有字段(API)

时间:2022-04-21 07:32:40

一旦 数据模型 创建完毕, 自然会有存取数据的需要.本文档介绍了由 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"开头的问题的所有民意测验.