QuerySet API参考

何时对查询集求值

本质上,可以创建、过滤、切片和传递查询集而不用真实操作数据库。在你对查询集做求值之前,不会发生任何实际的数据库操作。

你可以使用下列方法对查询集求值:

  • 迭代。queryset是可迭代的,它在首次迭代查询集时执行实际的数据库查询。例如, 下面的语句会将数据库中所有Entry 的headline 打印出来:

    for e in Entry.objects.all():
        print(e.headline)

    注意:不要使用上面的语句来验证在数据库中是否至少存在一条记录。使用 exists()方法更高效。

  • 切片。一个未求值的查询集进行切片通常返回另一个未求值的QuerySet,但是如果你使用切片的”step“参数,Django 将执行数据库查询并返回一个列表。对一个已经求值的查询集进行切片将返回一个列表。还要注意,虽然对未求值的查询集进行切片返回另一个未求值的查询集,但是却不不可以进一步修改它了(例如,添加更多的Filter,或者修改排序的方式),因为这将不太好翻译成SQL而且含义也不清晰。

  • 序列化/缓存。 序列化查询集的细节参见下面一节。本节提到它的目的是强调序列化将读取数据库

  • repr()。 当对查询集调用repr() 时,将对它求值。这是为了在Python 交互式解释器中使用的方便,这样你可以在交互式使用这个API 时立即看到结果。

  • len()。 当你对查询集调用len() 时, 将对它求值。正如你期望的那样,返回一个查询结果集的长度。

  • list()。 对查询集调用list() 将强制对它求值。例如:

    entry_list = list(Entry.objects.all())
  • bool()。 测试一个查询集的布尔值,例如使用bool()、or、and 或者if 语句将导致查询集的执行。如果至少有一个记录,则查询集为True,否则为False。例如:

    if Entry.objects.filter(headline="Test"):
       print("There is at least one Entry with the headline Test")

    注:如果你需要知道是否存在至少一条记录(而不需要真实的对象),使用 exists() 将更加高效。

Pikle 查询集

如果你Pickle一个查询集,它将在Pickle 之前强制将所有的结果加载到内存中。Pickle 通常用于缓存之前,并且当缓存的查询集重新加载时,你希望结果已经存在随时准备使用(从数据库读取耗费时间,就失去了缓存的目的)。这意味着当你Unpickle查询集时,它包含Pickle 时的结果,而不是当前数据库中的结果。

如果此后你只想Pickle 必要的信息来从数据库重新创建查询集,可以Pickle查询集的query 属性。然后你可以使用类似下面的代码重新创建原始的查询集(不用加载任何结果):

>>> import pickle
>>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query            # Restore the original 'query'.

query 是一个不透明的对象。它表示查询的内部构造,不属于公开的API。然而,这里讲到的Pickle 和Unpickle 这个属性的内容是安全的(和完全支持的)。

不可以在不同版本之间共享Pickle 的结果

 

查询集 API

下面是对于查询集的正式定义:

class QuerySet([model=Nonequery=Noneusing=None])[source]

     通常你在使用QuerySet时会以链式的filter 来使用。为了让这个能工作,大部分QuerySet 方法返回新的     QuerySet。这些方法在本节将详细讲述。

    QuerySet 类具有两个公有属性用于内省:

         ordered[source]

             如果QuerySet 是排好序的则为True —— 例如有一个order_by() 子句或者模型有默认的排序。否则为False .

        db[source]

             如果现在执行,则返回将使用的数据库。

返回新的查询集 的方法

annotate

annotate(*args**kwargs)

使用提供的查询表达式Annotate 查询集中的每个对象。查询表达式可以是一个简单的值、模型(或关联模型)字段的一个引用或对查询集中的对象一个聚合函数(平均值、和等)。

annotate() 的每个参数都是一个annotation,它将添加到返回的QuerySet 中每个对象。

Django 提供的聚合函数在下文的聚合函数文档中讲述。

关键字参数指定的Annotation 将使用关键字作为Annotation 的别名。匿名的参数的别名将基于聚合函数的名称和模型的字段生成。只有引用单个字段的聚合表达式才可以使用匿名参数。其它所有形式都必须用关键字参数。

from django.db.models import Count
q = Blog.objects.annotate(Count('entry'))
q
<QuerySet [<Blog: Beatles Blog>, <Blog: SUN Blog>, <Blog: my blog>, <Blog: my blog>]>
q[0].entry__count   # 匿名的参数的别名将基于聚合函数的名称和模型的字段生成
2
q[1].entry__count
0

Blog 模型本身没有定义entry__count 属性,但是通过使用一个关键字参数来指定聚合函数,你可以控制Annotation 的名称:

>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
order_by

order_by(*fields)

默认情况下,QuerySet 根据模型Meta 类的ordering 选项排序。你可以使用order_by 方法给每个QuerySet 指定特定的排序

随机排序:

Entry.objects.order_by('?')

注:order_by('?') 查询可能耗费资源且很慢,这取决于使用的数据库。

若要按照另外一个模型中的字段排序,可以使用查询关联模型时的语法。即通过字段的名称后面跟上两个下划线(__),再跟上新模型中的字段的名称,直至你希望连接的模型。例如:

Entry.objects.order_by('blog__name', 'headline')

如果Blog 中的Meta设置ordering = ['name'],那么

Entry.objects.order_by('blog')

等同于:

Entry.objects.order_by('blog__name')

通过关联字段排序QuerySet 还能够不用带来JOIN 产生的花费,方法是引用关联字段的_id:

# No Join
Entry.objects.order_by('blog_id')
# Join
Entry.objects.order_by('blog__id')

没有方法指定排序是否考虑大小写。对于大小写的敏感性,Django 将根据数据库中的排序方式排序结果。

你可以通过Lower将一个字段转换为小写来排序,它将达到大小写一致的排序:

Entry.objects.order_by(Lower('headline').desc())

如果你还用到distinct(),在根据关联模型中的字段排序时要小心。distinct() 中有一个备注讲述关联模型的排序如何对结果产生影响。

    指定一个多值字段来排序结果(例如,一个ManyToManyField 字段或者ForeignKey 字段的反向关联)。

考虑下面的情况:

class Event(Model):
   parent = models.ForeignKey('self', related_name='children')
   date = models.DateField()

Event.objects.order_by('children__date')

这里,每个Event 可能有多个潜在的排序数据;each Event with multiple children will be returned multiple times into the new QuerySet that order_by() creates. 换句话说, 用 order_by()方法对 QuerySet对象进行操作会返回一个扩大版的新QuerySet对象——新增的条目也许并没有什么卵用,你也用不着它们。

因此,当你使用多值字段对结果进行排序时要格外小心如果,您可以确保每个订单项只有一个订购数据,这种方法不会出现问题。如果不确定,请确保结果是你期望的

如果你不想对查询做任何排序,即使是默认的排序,可以不带参数调用order_by()。你可以通过检查QuerySet.ordered 属性来知道查询是否是排序的,如果QuerySet 有任何方式的排序它将为True。

每个order_by() 都将清除前面的任何排序。例如,下面的查询将按照pub_date 排序,而不是headline:

Entry.objects.order_by('headline').order_by('pub_date')

 

reverse

reverse() 方法反向排序QuerySet 中返回的元素。第二次调用reverse() 将恢复到原有的排序。

获取QuerySet 中最后五个元素,你可以这样做:

my_queryset.reverse()[:5]

QuerySet不支持倒着切片,因为无法利用sql高效实现。

同时还要注意,reverse() 应该只在一个已经定义排序的QuerySet 上调用(例如,在一个定义了默认排序的模型上,或者使用order_by() 的时候)。如果QuerySet 没有定义排序,调用reverse() 将不会有任何效果(在调用reverse() 之前没有定义排序,那么调用之后仍保持没有定义)。

 

distinct

distinct([*fields])

返回一个在SQL 查询中使用SELECT DISTINCT 的新QuerySet。它将去除查询结果中重复的行。

order_by() 调用中的任何字段都将包含在SQL 的 SELECT 列中。与distinct() 一起使用时可能导致预计不到的结果。如果你根据关联模型的字段排序,这些fields将添加到查询的字段中,它们可能产生本应该是唯一的重复的行。因为多余的列没有出现在返回的结果中(它们只是为了支持排序),有时候看上去像是返回了不明确的结果。

类似地,如果您使用values()查询来限制所选择的列,则仍然会涉及任何order_by()(或默认模型排序)影响结果的唯一性。

这里的约束是,如果你使用的是distinct(),请注意相关模型的排序。类似地,当一起使用distinct()和values()时,请注意字段在不在values()

 

values

values(*fields)

返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。

每个字典表示一个对象,键对应于模型对象的属性名称

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
[<Blog: Beatles Blog>]

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]

values() 接收可选的位置参数*fields,它指定SELECT 应该限制哪些字段。如果指定字段,每个字典将只包含指定的字段的键/值。如果没有指定字段,每个字典将包含数据库表中所有字段的键和值

Blog.objects.values('id', 'name')
<QuerySet [{'id': 3, 'name': 'Beatles Blog'}]>
  • 当values() 与distinct() 一起使用时,注意排序可能影响最终的结果。详细信息参见distinct() 中的备注。

  • 如果values() 子句位于extra() 调用之后,extra() 中的select 参数定义的字段必须显式包含在values() 调用中。values() 调用后面的extra() 调用将忽略选择的额外的字段。

  • 在values() 之后调用only() 和defer() 不太合理,所以将引发一个NotImplementedError。

你可以通过OneToOneField、ForeignKey 和 ManyToManyField 属性反向引用关联的模型的字段:

Blog.objects.values('name', 'entry__headline')
<QuerySet [{'entry__headline': 'this is headline', 'name': 'Beatles Blog'}, {'entry__headline': 'everything is the same', 'name': 'Beatles Blog'}, {'entry__headline': None, 'name': 'SUN Blog'}]>

警告

因为ManyToManyField 字段和反向关联可能有多个关联的行,包含它们可能导致结果集的倍数放大。如果你在values() 查询中包含多个这样的字段将更加明显,这种情况下将返回所有可能的组合

values_list

values_list(*fieldsflat=False)

与values() 类似,只是在迭代时返回的是元组而不是字典。每个元组包含传递给values_list() 调用的字段的值 —— 所以第一个元素为第一个字段,以此类推。例如

Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'this is headline'), (2, 'everything is the same')]>

只传递一个字段,你还可以传递flat 参数。如果为True,它表示返回的结果为单个值而不是元组。传递多个字段,传递flat会报错

Entry.objects.values_list('id')
<QuerySet [(1,), (2,)]>
Entry.objects.values_list('id', flat=True)
<QuerySet [1, 2]>

 

dates

dates(fieldkindorder='ASC')

返回DateQuerySet - QuerySet,其计算结果为datetime.date对象列表,表示特定种类的所有可用日期QuerySet。

field应为模型的DateField的名称。 kind应为"year"、"month"或"day"。隐式的是升序排序。若要随机排序,请使用"?",像这样:

  • "year" 返回对应该field的所有不同年份值的list。
  • “month”返回字段的所有不同年/月值的列表。
  • “day”返回字段的所有不同年/月/日值的列表。
Entry.objects.dates('pub_date', 'year')
<QuerySet [datetime.date(2008, 1, 1), datetime.date(2017, 1, 1)]>
Entry.objects.dates('pub_date', 'day')
<QuerySet [datetime.date(2008, 8, 16), datetime.date(2017, 8, 16)]>
Entry.objects.filter(headline__contains='is').dates('pub_date', 'day')
<QuerySet [datetime.date(2008, 8, 16), datetime.date(2017, 8, 16)]>

 

datetimes

datetimes(field_namekindorder='ASC'tzinfo=None)

返回QuerySet,其计算为datetime.datetime对象的列表,表示QuerySet内容中特定种类的所有可用日期。

field_name应为模型的DateTimeField的名称。

kind应为“year”,“month”,“day”,“hour”,“minute”或“second”。结果列表中的每个datetime.datetime对象被“截断”到给定的类型。

order, 默认为'ASC', 可选项为'ASC' 或者 'DESC'. 这个选项指定了返回结果的排序方式。

tzinfo定义在截断之前将数据时间转换到的时区。实际上,给定的datetime具有不同的表示,这取决于使用的时区。此参数必须是datetime.tzinfo对象。如果它无,Django使用当前时区。当USE_TZ为False时,它不起作用。

注意

此函数直接在数据库中执行时区转换。因此,您的数据库必须能够解释tzinfo.tzname(None)的值。这转化为以下要求:

none

none()

调用none()将创建一个从不返回任何对象的查询集,并且在访问结果时不会执行任何查询。qs.none()查询集是EmptyQuerySet的一个实例。

from django.db.models.query import EmptyQuerySet
isinstance(Entry.objects.none(), EmptyQuerySet)
True
all

all()

返回当前QuerySet(或QuerySet 子类) 的副本。它可以用于在你希望传递一个模型管理器或QuerySet 并对结果做进一步过滤的情况。不管对哪一种对象调用all(),你都将获得一个可以工作的QuerySet。

当对QuerySet进行求值时,它通常会缓存其结果。如果数据库中的数据在QuerySet求值之后可能已经改变,你可以通过在以前求值过的QuerySet上调用相同的all() 查询以获得更新后的结果。

 

select_related

select_related(*fields)

返回一个QuerySet,当执行它的查询时它沿着外键关系查询关联的对象的数据。它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。

一般查询:

# 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

沿着外键查询。如果你有以下模型:

from django.db import models

class City(models.Model):
    # ...
    pass

class Person(models.Model):
    # ...
    hometown = models.ForeignKey(City)

class Book(models.Model):
    # ...
    author = models.ForeignKey(Person)

Book.objects.select_related('author__hometown').get(id=4) 调用将缓存关联的Person 关联的City:

b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author         # Doesn't hit the database.
c = p.hometown       # Doesn't hit the database.

b = Book.objects.get(id=4) # No select_related() in this example.
p = b.author         # Hits the database.
c = p.hometown       # Hits the database.

清除QuerySet 上以前的select_related 添加的关联字段,可以传递一个None 作为参数:

without_relations = queryset.select_related(None)
prefetch_related

prefetch_related(*lookups)

返回QuerySet,它将在单个批处理中自动检索每个指定查找的相关对象。

详解

 

extra

extra(select=Nonewhere=Noneparams=Nonetables=Noneorder_by=Noneselect_params=None)

有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet修改机制 — 它能在 QuerySet生成的SQL从句中注入新子句

警告

无论何时你都需要非常小心的使用extra(). 每次使用它时,您都应该转义用户可以使用params控制的任何参数,以防止SQL注入攻击。请详细了解SQL injection protection。尽量避免写 extra。

详解

defer

defer(*fields)

在一些复杂的数据建模情况下,您的模型可能包含大量字段,其中一些可能包含大量数据(例如,文本字段),或者需要昂贵的处理来将它们转换为Python对象。如果您在某些情况下使用查询集的结果,当您最初获取数据时不知道是否需要这些特定字段,可以告诉Django不要从数据库中检索它们

 详解

only

only(*fields)

only()方法或多或少与defer()相反。您调用它时,应该在检索模型时延迟的字段。如果你有一个模型几乎所有的字段需要延迟,使用only()指定补充的字段集可以导致更简单的代码。

using

using(alias)

如果你使用多个数据库,这个方法用于控制QuerySet 将在哪个数据库上求值。这个方法的唯一参数是数据库的别名,定义在DATABASES

例如:

# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')

 

select_for_update

select_for_update(nowait=False)

返回一个 queryset  ,会锁定相关行直到事务结束。在支持的数据库上面产生一个SELECT ... FORUPDATE语句

例如:

entries = Entry.objects.select_for_update().filter(author=request.user)

所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。

raw

raw(raw_queryparams=Nonetranslations=None)

接收一个原始的SQL 查询,执行它并返回一个django.db.models.query.RawQuerySet 实例。这个RawQuerySet实例可以迭代以提供实例对象,就像普通的QuerySet 一样。

更多信息参见执行原始的SQL 查询

警告

raw() 永远触发一个新的查询,而与之前的filter 无关。因此,它通常应该从Manager 或一个全新的QuerySet 实例调用。

不会返回QuerySets的方法

 

create

create(**kwargs)

一个在一步操作中同时创建对象并且保存的便捷方法. 如此一来:

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

和:

p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)

是等同的.

参数 force_insert 在其他的文档中有介绍, 它意味着一个新的对象一定会被创建. 正常情况中,你不必要担心这点. 然而, 如果你的model中有一个你手动设置主键, 并且这个值已经存在于数据库中, 调用 create()将会失败并且触发IntegrityError 因为主键必须是唯一的. 如果你手动设置了主键,做好异常处理的准备.

 

get_or_create

get_or_create(defaults=None**kwargs)

 

返回一个由(object, created)组成的元组,元组中的object 是一个查询到的或者是被创建的对象, created 是一个表示是否创建了新的对象的布尔值(True 表示创建对象,False表示查询到对象)。

这主要用作样板代码的一种快捷方式。例如:

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()

如果模型的字段数量较大的话,这种模式就变的非常不易用了。上面的示例可以用get_or_create()重写  :

obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
                  defaults={'birthday': date(1940, 10, 9)})

 新对象创建逻辑:

params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update(defaults)
obj = self.model(**params)
obj.save()

使用MySQL,请确保使用READ COMMITTED 隔离级别而不是默认的REPEATABLE READ,否则你将会遇到get_or_create 引发IntegrityError 但对象在接下来的get() 调用中并不存在的情况

get_or_create() 在Django 视图中的使用。请确保只在POST 请求中使用

你可以通过ManyToManyField 属性和反向关联使用get_or_create()。在这种情况下,你应该限制查询在关联的上下文内部。如果你不一致地使用它,将可能导致完整性问题。

根据下面的模型:

class Chapter(models.Model):
    title = models.CharField(max_length=255, unique=True)

class Book(models.Model):
    title = models.CharField(max_length=256)
    chapters = models.ManyToManyField(Chapter)

你可以通过Book 的chapters 字段使用get_or_create(),但是它只会获取该Book 内部的上下文:

>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError

发生这个错误时因为它尝试通过Book “Ulysses” 获取或者创建“Chapter 1”,但是它不能:关联关系不能获取这个chapter 因为它与这个book 不关联,但因为title 字段是唯一的它仍然不能创建。

update_or_create

update_or_create(defaults=None**kwargs)

一个通过给出的kwargs 来更新对象的便捷方法, 如果需要的话创建一个新的对象。defaults 是一个由 (field, value) 对组成的字典,用于更新对象。

返回一个由 (object, created)组成的元组,元组中的object 是一个创建的或者是被更新的对象, created 是一个标示是否创建了新的对象的布尔值。

update_or_create 方法尝试通过给出的kwargs 去从数据库中获取匹配的对象。如果找到匹配的对象,它将会依据defaults 字典给出的值更新字段。

这用作样板代码的一种快捷方式。例如:

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()

如果模型的字段数量较大的话,这种模式就变的非常不易用。上面的示例可以用 update_or_create() 重写:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon', defaults=updated_values)

kwargs 中的名称如何解析的详细描述可以参见get_or_create()

和上文描述的get_or_create() 一样,这个方式容易导致竞态条件,如果数据库层级没有前置唯一性它会让多行同时插入。

in_bulk

in_bulk(id_list)

获取主键值的列表,并返回将每个主键值映射到具有给定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([])
{}

如果你传递in_bulk()一个空列表,你会得到一个空的字典。

iterator

iterator()

评估QuerySet(通过执行查询),并返回一个迭代器(参见 PEP 234)。QuerySet通常在内部缓存其结果,以便在重复计算是不会导致额外的查询。相反,iterator()将直接读取结果,而不在QuerySet级别执行任何缓存(内部,默认迭代器调用iterator()并高速缓存返回值)。对于返回大量只需要访问一次的对象的QuerySet,这可以带来更好的性能和显着减少内存。

请注意,在已经求值了的QuerySet上使用iterator()会强制它再次计算,重复查询。

此外,使用iterator()会导致先前的prefetch_related()调用被忽略,因为这两个优化一起没有意义。

 

latest

latest(field_name=None)

使用作为日期字段提供的field_name,按日期返回表中的最新对象。

此示例根据pub_date字段返回表中的最新条目:

Entry.objects.latest('pub_date')

如果模型的Meta指定get_latest_by,则可以将field_name参数留给earliest()或者 latest()。默认情况下,Django将使用get_latest_by中指定的字段。

get(),earliest()和latest() raise DoesNotExist参数。

请注意,earliest()和latest()仅仅是为了方便和可读性。

 

earliest

earliest(field_name=None)

除非方向更改,否则像latest()

first

first()

返回结果集的第一个对象, 当没有找到时返回None.如果 QuerySet 没有设置排序,则将会自动按主键进行排序

例:

p = Article.objects.order_by('title', 'pub_date').first()

笔记:first() 是一个简便方法 下面这个例子和上面的代码效果是一样

try:
    p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
    p = None
aggregate(聚合查询)

aggregate(*args**kwargs)

返回一个字典,包含根据QuerySet 计算得到的聚合值(平均数、和等等)。aggregate() 的每个参数指定返回的字典中将要包含的值。

Django 提供的聚合函数在下文的聚合函数中讲述。因为聚合也是查询表达式,你可以组合多个聚合以及值来创建复杂的聚合。

使用关键字参数指定的聚合将使用关键字参数的名称作为Annotation 的名称。匿名的参数的名称将基于聚合函数的名称和模型字段生成。复杂的聚合不可以使用匿名参数,它们必须指定一个关键字参数作为别名。

例如,当你使用Blog Entry 时,你可能想知道对Author 贡献的Blog Entry 的数目:

>>> 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 包含任何结果,则返回True,否则返回False。它会试图用最简单和最快的方法完成查询,但它执行的方法与普通的QuerySet 查询确实几乎相同。

exists() 用于搜寻对象是否在QuerySet 中以及QuerySet 是否存在任何对象,特别是QuerySet 比较大的时候。

查找具有唯一性字段(例如primary_key)的模型是否在一个QuerySet 中的最高效的方法是:

entry = Entry.objects.get(pk=123)
if Blog.objects.filter(pk=entry.pk).exists():
    print("Entry contained in queryset")

 

update

update(**kwargs)

对指定的字段执行SQL更新查询,并返回匹配的行数(如果某些行已具有新值,则可能不等于已更新的行数)。

Entry.objects.filter(pub_date__year=2008).update(headline='update headline')
1

update()方法立即应用,对更新的QuerySet的唯一限制是它只能更新模型主表中的列,而不是相关模型。你不能这样做,例如:

>>> Entry.objects.update(blog__name='foo') # Won't work!
不能在已经计算值QuerySet上调用update(),该查询已截取一个切片,或者无法再进行过滤。

 

delete

delete()

QuerySet中的所有行执行SQL删除查询。立即应用delete()。您不能在QuerySet上调用delete(),该查询已采取切片或以其他方式无法过滤。

例如,要删除特定博客中的所有条目:

>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()

默认情况下,Django的ForeignKey模拟SQL约束ON DELETE CASCADE字,任何具有指向要删除的对象的外键的对象将与它们一起被删除。例如:

blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
blogs.delete()

此级联行为可通过ForeignKeyon_delete参数自定义。

delete()方法执行批量删除,并且不会在模型上调用任何delete()方法。但它会为所有已删除的对象(包括级联删除)发出pre_deletepost_delete信号。

Django需要获取对象到内存中以发送信号和处理级联。然而,如果没有级联和没有信号,那么Django可以采取快速路径并删除对象而不提取到内存中。对于大型删除,这可以显着减少内存使用。执行的查询量也可以减少。

设置为on_delete DO_NOTHING的外键不会阻止删除快速路径。

请注意,在对象删除中生成的查询是实施详细信息,可能会更改。

 

as_manager

classmethod as_manager()

类方法,返回Manager的实例与QuerySet的方法的副本

 

字段查找

range

范围测试(包含于之中)。

例:

import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

SQL等效:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
 
day

对于日期和日期时间字段,具体到某一天的匹配。取一个整数的天数。

例:

Entry.objects.filter(pub_date__day=3)

SQL等效:

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';

(确切的SQL语法因每个数据库引擎而异)。

请注意,这将匹配每月第三天(例如1月3日,7月3日等)的任何包含pub_date的记录。

USE_TZ为True时,在过滤之前,datetime字段将转换为当前时区。这需要数据库中的time zone definitions in the database

search

一个Boolean类型的全文搜索,以全文搜索的优势。这个很像 contains ,但是由于全文索引的优势,以使它更显著的快。

例:

Entry.objects.filter(headline__search="+Django -jazz Python")

SQL等效:

SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);

注意,这仅在MySQL中可用,并且需要直接操作数据库以添加全文索引,请参阅MySQL文档

 

iregex

不区分大小写的正则表达式匹配。

例:

Entry.objects.get(title__iregex=r'^(an?|the) +')

SQL等价物:

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

 

聚合函数

Django 的django.db.models 模块提供以下聚合函数。关于如何使用这些聚合函数的细节,参见聚合函数的指南。关于如何创建聚合函数,参数聚合函数 的文档。

警告

SQLite 不能直接处理日期/时间字段的聚合。这是因为SQLite 中没有原生的日期/时间字段,Django 目前使用文本字段模拟它的功能。在SQLite 中对日期/时间字段使用聚合将引发NotImplementedError。

在QuerySet 为空时,聚合函数函数将返回None。 例如,如果QuerySet 中没有记录,Sum 聚合函数将返回None 而不是0。Count 是一个例外,如果QuerySet 为空,它将返回0。

所有聚合函数具有以下共同的参数:

expression

引用模型字段的一个字符串,或者一个查询表达式

New in Django 1.8:

现在在复杂的计算中,聚合函数可以引用多个字段。

output_field

用来表示返回值的模型字段,它是一个可选的参数。

New in Django 1.8:

添加output_field 参数。

在组合多个类型的字段时,只有在所有的字段都是相同类型的情况下,Django 才能确定output_field。否则,你必须自己提供output_field 参数。

**extra

这些关键字参数可以给聚合函数生成的SQL 提供额外的信息。

avg

class Avg(expressionoutput_field=None**extra)

返回给定expression 的平均值,其中expression 必须为数值。

  • 默认的别名:<field>__avg
  • 返回类型:float
Count

class Count(expressiondistinct=False**extra)

返回与expression 相关的对象的个数。

  • 默认的别名:<field>__count
  • 返回类型:int

有一个可选的参数:

distinct

如果distinct=True,Count 将只计算唯一的实例。它等同于COUNT(DISTINCT <field>) SQL 语句。默认值为False。

Max

class Max(expressionoutput_field=None**extra)

返回expression 的最大值。

  • 默认的别名:<field>__max
  • 返回类型:与输入字段的类型相同,如果提供则为 output_field 类型
Min

class Min(expressionoutput_field=None**extra)

返回expression 的最小值。

  • 默认的别名:<field>__min
  • 返回的类型:与输入字段的类型相同,如果提供则为 output_field 类型
StdDev

class StdDev(expressionsample=False**extra)

返回expression 的标准差。

  • 默认的别名:<field>__stddev
  • 返回类型:float

有一个可选的参数:

sample

默认情况下,StdDev 返回群体的标准差。但是,如果sample=True,返回的值将是样本的标准差。

SQLite

SQLite 没有直接提供StdDev。有一个可用的实现是SQLite 的一个扩展模块。参见SQlite 的文档 中获取并安装这个扩展的指南。

Sum

class Sum(expressionoutput_field=None**extra)

计算expression 的所有值的和。

  • 默认的别名:<field>__sum
  • 返回类型:与输入的字段相同,如果提供则为output_field 的类型
Variance

class Variance(expressionsample=False**extra)

返回expression 的方差。

  • 默认的别名:<field>__variance
  • 返回的类型:float

有一个可选的参数:

sample

默认情况下,Variance 返回群体的方差。但是,如果sample=True,返回的值将是样本的方差。

SQLite

SQLite 没有直接提供Variance。有一个可用的实现是SQLite 的一个扩展模块。 参见SQlite 的文档 中获取并安装这个扩展的指南。

 

查询相关的类

本节提供查询相关的工具的参考资料,它们其它地方没有文档。

Q() 对象

Prefetch()对象

New in Django 1.7.

class Prefetch(lookupqueryset=Noneto_attr=None)

Prefetch()对象可用于控制prefetch_related()的操作。

lookup参数描述了跟随的关系,并且工作方式与传递给prefetch_related()的基于字符串的查找相同。例如:

>>> Question.objects.prefetch_related(Prefetch('choice_set')).get().choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# This will only execute two queries regardless of the number of Question
# and Choice objects.
>>> Question.objects.prefetch_related(Prefetch('choice_set')).all()
[<Question: Question object>]

查询集参数为给定的查找提供基本QuerySet。这对于进一步过滤预取操作或从预取关系调用select_related()很有用,因此进一步减少查询数量:

>>> voted_choices = Choice.objects.filter(votes__gt=0)
>>> voted_choices
[<Choice: The sky>]
>>> prefetch = Prefetch('choice_set', queryset=voted_choices)
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
[<Choice: The sky>]

to_attr参数将预取操作的结果设置为自定义属性:

>>> prefetch = Prefetch('choice_set', queryset=voted_choices, to_attr='voted_choices')
>>> Question.objects.prefetch_related(prefetch).get().voted_choices
[<Choice: The sky>]
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

注意

当使用to_attr时,预取的结果存储在列表中。这可以提供比存储在QuerySet实例内的缓存结果的传统prefetch_related调用显着的速度改进。

 

转载于:https://my.oschina.net/acutesun/blog/1511333

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值