QuerySets evaluated
可以创建、过滤、切片和传递查询集而不用真实操作数据库。在你对查询集做求值之前,不会发生任何实际的数据库操作。
对于查询集我们使用以下方法进行求值:
- Iteration
- Slicing
- Pickling/Caching
- repr()
- len()
- list()
- bool()
QuerySet API
返回新的查询集方法
- filter
返回一个新的 QuerySet 包含给定参数的查询匹配对象,更复杂的查询可以使用 Q 对象。
- exclude
返回一个新的 QuerySet,它包含不满足给定的查找参数的对象,更复杂的查询同样可以使用 Q 对象。
- annotate
使用提供的查询表达式给 QuerySet 的每个对象增加注释,可以理解为增加一个新的属性。
查询表达式可以是一个简单的值、模型(或关联模型)字段的一个引用或对查询集中的对象一个聚合函数(平均值、和等)
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
>>> q[0].name
'Blogasaurus'
>>> q[0].entry__count # 新增的 entry__count 属性
42
# 指定注释名称
>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
>>> q[0].number_of_entries
42
使用 annotate 需要用 django.db.models 的统计方法。除了 Count 统计方法之外,还有 Max、Min、Sum、Avg 等方法。
- order_by
指定 QuerySet 排序
# 升序
>>> Author.objects.filter().order_by('name')
<QuerySet [<Author: abner>, <Author: mike>]>
# 降序
>>> Author.objects.filter().order_by('-name')
<QuerySet [<Author: mike>, <Author: abner>]>
# 随机排序,不推荐使用(速度慢、查询昂贵)
>>> Author.objects.order_by('?')
- reverse
反向排序 QuerySet 中返回的元素
- distinct
返回一个新的 QuerySet 并去除查询结果中的重复的行
>>> CompileRules.objects.values('business__name').distinct()
<QuerySet [{'business__name': 'img.ppdai.com'}, {'business__name': 'api.alert.risk.ppdaicorp.com'}, {'business__name': 'api.antifraud.risk.ppdaicorp.com'}, {'business__name': 'chargingjob.ppdapi.com'}]>
>>> rules = CompileRules.objects.distinct().values_list('business__name')
>>> [i[0] for i in rules]
['img.ppdai.com','api.alert.risk.ppdaicorp.com','api.antifraud.risk.ppdaicorp.com','chargingjob.ppdapi.com']
- values
把 QuerySets 当作迭代器使用,返回一个字典,而不是模型实例
>>> Author.objects.filter(name='abner').values()
<QuerySet [{'id': 2, 'name': 'abner', 'email': 'abner@163.com'}, {'id': 3, 'name': 'abner', 'email': 'abner@qq.com'}]>
# 指定字段
>>> Author.objects.values('name')
<QuerySet [{'name': 'abner'},{'name': 'abner'},v{'name': 'mike'}]>
# 数据库函数,Lower 返回小写形式
>>> from django.db.models.functions import Lower
>>> Author.objects.values(lower=Lower('name'))
<QuerySet [{'lower': 'dkey'}, {'lower': 'jerry'}, {'lower': 'jerry'}]>
- values_list
以元组的形式返回查询集,可以返回特定字段的值,也可以是列表的形式
>>> Business.objects.filter(level=1).values_list('id', 'name')
<TreeQuerySet [(3, '借入运营'), (106, '借入借贷'), (219, '数据决策平台'), (225, '数据架构'), (234, '测试')]>
>>> Business.objects.filter(level=1).values_list('name', flat=True)
<TreeQuerySet ['借入运营', '借入借贷', '数据决策平台', '数据架构', '测试']>
- dates
dates(field, kind, order='ASC’)
返回 datetime.date 对象列表,查询的字段应该是 DateField 模型,kind应为"year”、“month"或"day”。隐式的是升序排序
1.year:返回字段不同年份值列表
2.month:返回字段所有不同年/月值列表
3.day:返回字段所有不同年/月/日值列表
- datetimes
datetimes(field_name, kind, order='ASC’, tzinfo=None)
返回 datetime.datetimes 对象列表,查询的字段应该是 DateField 模型,kind应为"year”、“month"或"day”。隐式的是升序排序
- none
创建一个不返回任何对象的查询集,访问结果时不会执行任何查询。
>>> Entry.objects.none()
[]
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True
- all
所有查询集
- select_related
对于 ForeignKey 和 OneToOneField 等字段,通过添加 select_related,可以把相关的对象在一次查询中查出,之后使用时就不需要再次查数据库
返回一个新的查询集,沿着外键查询关联对象的数据。它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。
# 普通查询
# Hits the database.
e = Entry.objects.get(id=5)
# Hits the database again to get the related Blog object.
b = e.blog
#select_related 查询
# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)
# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
- prefetch_related
prefetch_related 对于相关对象会进行一次独立的查询,然后在 Python 中把对象关联起来。所以prefetch_related可以用于many-to-many and many-to-one关系
- extra
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet 修改机制 — 它能在 QuerySet生成的SQL从句中注入新子句
extra可以指定一个或多个参数,例如 select, where or tables。 这些参数都不是必须的,但是你至少要使用一个
- defer
排除不需要的字段,降低性能损耗
- only
仅选择需要的字段
- using
using(alias) // alias 数据库别名
如果使用多个数据库,改方法可以控制从哪个数据库上求值。
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')
- select_for_update
返回一个 queryset ,会锁定相关行直到事务结束
entries = Entry.objects.select_for_update().filter(author=request.user)
所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。
- raw
接收一个原始的SQL 查询,执行它并返回一个django.db.models.query.RawQuerySet 实例
Django提供两种方法使用原始SQL进行查询:一种是使用Manager.raw()方法,进行原始查询并返回模型实例;另一种是完全避开模型层,直接执行自定义的SQL语句。
>>> raw = Author.objects.raw('select * from polls_author')
>>> type(raw)
<class 'django.db.models.query.RawQuerySet'>
不返回新的查询集
- get
返回按照参数匹配的对象
- create
创建并保存对象
- get_or_create
通过给定参数来查询对象,如果对象不存在则会创建一个新的对象
返回一个由(object, created)组成的元组,元组中的object 是一个查询到的或者是被创建的对象, created 是一个表示是否创建了新的对象的布尔值。
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
obj.save()
# use get_or_create
obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
defaults={'birthday': date(1940, 10, 9)})
任何传递给 get_or_create() 的关键字参数,除了一个可选的defaults,都将传递给get() 调用
get_or_create() 在Django 视图中的使用。请确保只在POST 请求中使用,除非你有充分的理由。GET 请求不应该对数据有任何影响。而POST 则用于对数据产生影响的请求
- update_or_create
通过给定参数来更新对象,如果对象不存在则会创建一个新的对象
一个通过给出的kwargs 来更新对象的便捷方法, 如果需要的话创建一个新的对象。defaults 是一个由 (field, value) 对组成的字典,用于更新对象
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
for key, value in updated_values.iteritems():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
updated_values.update({'first_name': 'John', 'last_name': 'Lennon'})
obj = Person(**updated_values)
obj.save()
# use update_or_create
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon', defaults=updated_values)
和上文描述的get_or_create() 一样,这个方式容易导致竞态条件,如果数据库层级没有前置唯一性它会让多行同时插入。
- bulk_create
批量写入数据
- count
返回 QuerySet 对象个数
- in_bulk
获取主键值的列表,并返回将每个主键值映射到具有给定ID的对象的实例的字典。
>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
- iterator
- latest:使用作为日期字段提供的field_name,按日期返回表中的最新对象
- earliest
- first
- last
- aggregate:聚合查询
返回一个字典,包含根据QuerySet 计算得到的聚合值(平均数、和等等)。aggregate() 的每个参数指定返回的字典中将要包含的值
>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}
>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}
- exists
exists() 用于搜寻对象是否在QuerySet 中以及QuerySet 是否存在任何对象,特别是QuerySet 比较大的时候。
# exists 方法比普通方法快
entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
print("Entry contained in queryset")
# 普通方法
if entry in some_queryset:
print("Entry contained in QuerySet")
# 判断 queryset 是否含有对象,exists 比普通判断快特别是查询集比较大的情况下
if some_queryset.exists():
print("There is at least one object in some_queryset")
if some_queryset:
print("There is at least one object in some_queryset")
- update
对指定的字段执行SQL更新查询,并返回匹配的行数
- delete
对QuerySet中的所有行执行SQL删除查询
- as_manager
字段查找
方法 | 含义 |
---|---|
exact | 精确匹配 |
iexact | 忽略大小写精确匹配 |
contains | 包含关系 |
icontains | 忽略大小写包含关系 |
in | 在给定的列表 |
gt | 大于 |
gte | 大于等于 |
lt | 小于 |
lte | 小于等于 |
startswith | 区分大小写,从开始位置匹配 |
istartswith | 不区分大小写,从开始位置匹配 |
endswith | 区分大小写,从结束位置匹 |
iendswith | 不区分大小写,从结束位置匹配 |
range | 范围测试(包含于之中) |
year | 对于日期和日期时间字段,年份匹配 |
month | 对于日期和日期时间字段,月份匹配 |
day | 对于日期和日期时间字段,天数匹配 |
week_day | 星期匹配 |
hour | 对于日期时间字段,精确的小时匹配 |
minute | 对于日期时间字段,精确的分钟匹配 |
second | 对于datetime字段,精确的秒匹配 |
isnull | 判断字段值为 True 或 False |
search | 一个Boolean类型的全文搜索,以全文搜索的优势 |
regex | 正则表达式 |
iregex | 不区分大小写的正则表达式匹配 |