Django-ORM(二之QuerySet)

来源:互联网 发布:php header image 编辑:程序博客网 时间:2024/06/06 17:14

QuerySet

可以使用对查询集求值的方法:

  • Iteration
  • Slicing
  • Pickling/Caching
  • repr()
  • len()
  • list()
  • bool()

查询集的正式定义:

1.定义

class QuerySet([model=None, query=None, using=None])

QuerySet公有属性用于内省

  • ordered,QuerySet是否排好序
  • db,返回将使用的数据库

2.返回新查询集的方法

filter(**kwargs)

返回一个新的QuerySet,包含与给定的查询参数匹配的对象。
查找的参数(**kwargs)应该满足下文字段查找中的格式。在底层的SQL 语句中,多个参数通过AND 连接。
如果你需要执行更复杂的查询(例如,使用OR 语句查询),你可以使用Q 对象。

exclude(**kwargs)

返回一个新的QuerySet,它包含不满足给定的查找参数的对象。
查找的参数(**kwargs)应该满足下文字段查找中的格式。 在底层的SQL 语句中,多个参数通过AND 连接,然后所有的内容放入NOT() 中。

annotate(*args, **kwargs)

使用提供的查询表达式Annotate 查询集中的每个对象。查询表达式可以是一个简单的值、模型(或关联模型)字段的一个引用或对查询集中的对象一个聚合函数(平均值、和等)。
关键字参数指定的Annotation 将使用关键字作为Annotation 的别名。匿名的参数的别名将基于聚合函数的名称和模型的字段生成。只有引用单个字段的聚合表达式才可以使用匿名参数。其它所有形式都必须用关键字参数。
例如,如果你正在操作一个Blog 列表,你可能想知道每个Blog 有多少Entry:

>>> from django.db.models import Count>>> q = Blog.objects.annotate(Count('entry'))# The name of the first blog>>> q[0].name'Blogasaurus'# The number of entries on the first blog>>> q[0].entry__count42

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_entries42

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

Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

上面的结果将按照pub_date 降序排序,然后再按照headline 升序排序。"-pub_date" 前面的负号表示降序排序。隐式的是升序排序。若要随机排序,请使用”?”,像这样:

Entry.objects.order_by('?')

若要按照另外一个模型中的字段排序,可以使用查询关联模型时的语法。

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

如果排序的字段与另外一个模型关联,Django 将使用关联的模型的默认排序,或者如果没有指定Meta.ordering 将通过关联的模型的主键排序。

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

# No JoinEntry.objects.order_by('blog_id')# JoinEntry.objects.order_by('blog__id')

reverse()
如果QuerySet 没有定义排序,调用reverse() 将不会有任何效果(在调用reverse() 之前没有定义排序,那么调用之后仍保持没有定义)。

distinct([*fields])
返回一个在SQL 查询中使用SELECT DISTINCT 的新QuerySet。它将去除查询结果中重复的行。

values(*fields)
返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。
下面的例子将values() 与普通的模型对象进行比较:

# 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': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],>>> Blog.objects.values('id', 'name')[{'id': 1, 'name': 'Beatles Blog'}]

最后,要注意ValuesQuerySet 是QuerySet 的子类,它实现了大部分相同的方法。你可以对它调用filter()、order_by() 等等。这表示下面的两个调用完全相同:

Blog.objects.values().order_by('id')Blog.objects.order_by('id').values()

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

>>> Entry.objects.values_list('id', 'headline')[(1, 'First entry'), ...]

如果只传递一个字段,你还可以传递flat 参数。如果为True,它表示返回的结果为单个值而不是元组。一个例子会让它们的区别更加清晰:

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

dates(field, kind, order=’ASC’)
返回DateQuerySet - QuerySet,其计算结果为datetime.date对象列表,表示特定种类的所有可用日期QuerySet。
field应为模型的DateField的名称。 kind应为”year”、”month”或”day”。隐式的是升序排序。若要随机排序,请使用”?”,像这样:

  • “year” 返回对应该field的所有不同年份值的list。
  • “month”返回字段的所有不同年/月值的列表。
  • “day”返回字段的所有不同年/月/日值的列表。

order(默认为“ASC”)应为’ASC’或’DESC’。
例子:

>>> Entry.objects.dates('pub_date', 'year')[datetime.date(2005, 1, 1)]>>> Entry.objects.dates('pub_date', 'month')[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]>>> Entry.objects.dates('pub_date', 'day')[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]>>> Entry.objects.dates('pub_date', 'day', order='DESC')[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')[datetime.date(2005, 3, 20)]

datetimes(field_name, kind, order=’ASC’, tzinfo=None)
返回QuerySet,其计算为datetime.datetime对象的列表,表示QuerySet内容中特定种类的所有可用日期。

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

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

select_related(*fields)
返回一个QuerySet,当执行它的查询时它沿着外键关系查询关联的对象的数据。它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。
下面的例子解释了普通查询和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

filter() 和select_related() 链的顺序不重要。下面的查询集是等同的:

Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())

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

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

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

only(*fields)
only()方法或多或少与defer()相反。您调用它时,应该在检索模型时延迟的字段。如果你有一个模型几乎所有的字段需要延迟,使用only()指定补充的字段集可以导致更简单的代码。
假设您有一个包含字段name, age和biography的模型。以下两个查询集是相同的,就延迟字段而言:

Person.objects.defer("age", "biography")Person.objects.only("name")

每当您调用only()时,取代立即加载的字段集。方法的名称是助记符:只有这些字段立即加载;其余的都被推迟。因此,对only()的连续调用仅导致所考虑的最后字段:

# This will defer all fields except the headline.Entry.objects.only("body", "rating").only("headline")

由于defer()以递增方式动作(向延迟列表中添加字段),因此您可以将调用结合到only()和defer()

# Final result is that everything except "headline" is deferred.Entry.objects.only("headline", "body").defer("body")# Final result loads headline and body immediately (only() replaces any# existing set of fields).Entry.objects.defer("body").only("headline", "body")

注意:
对具有延迟字段的实例调用save()时,仅保存加载的字段。有关详细信息,请参见save()。

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(nowait=False)
返回一个 queryset ,会锁定相关行直到事务结束。在支持的数据库上面产生一个SELECT … FORUPDATE语句
例如:

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

所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。
一般情况下如果其他事务锁定了相关行,那么本查询将被阻塞,直到锁被释放。如果这不是你想要的行为,请使用select_for_update(nowait=True). 这将使查询不阻塞。如果其它事务持有冲突的锁, 那么查询将引发 DatabaseError 异常.

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

3.不会返回QuerySet的方法

以下QuerySet方法不会返回某个QuerySet,而是用于评估QuerySet。这些方法不会使用告诉缓存,并且在每次调用时都会查询数据库。

get(**kwargs)
返回按照查询参数匹配到的对象,参数的格式应该符合 Field lookups的要求.
如果匹配到的对象个数不只一个的话,get() 将会触发MultipleObjectsReturned 异常. MultipleObjectsReturned 异常是模型类的属性.
如果根据给出的参数匹配不到对象的话,get() 将触发DoesNotExist 异常.

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)

是等同的。
如果你手动设置了主键,做好异常处理的准备。

get_or_create(defaults=None, **kwargs)
一个通过给出的kwargs 来查询对象的便捷方法(如果你的模型中的所有字段都有默认值,可以为空),需要的话创建一个对象。

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

bulk_create(objs, batch_size=None)
此方法以有效的方式(通常只有1个查询,无论有多少对象)将提供的对象列表插入到数据库中:

count()
返回在数据库中对应的 QuerySet.对象的个数。 count() 永远不会引发异常。

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([]){}

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

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中指定的字段。

earliest(field_name=None)
除非方向更改,否则像latest()。

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

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

last()
工作方式类似first(),只是返回的是查询集中最后一个对象。

aggregate(*args, **kwargs)
返回一个字典,包含根据QuerySet 计算得到的聚合值(平均数、和等等)。aggregate() 的每个参数指定返回的字典中将要包含的值。
使用关键字参数指定的聚合将使用关键字参数的名称作为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()
如果QuerySet 包含任何结果,则返回True,否则返回False。它会试图用最简单和最快的方法完成查询,但它执行的方法与普通的QuerySet 查询确实几乎相同。
exists() 用于搜寻对象是否在QuerySet 中以及QuerySet 是否存在任何对象,特别是QuerySet 比较大的时候。
查找具有唯一性字段(例如primary_key)的模型是否在一个QuerySet 中的最高效的方法是:

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

若要查找一个QuerySet 是否包含任何元素:

if some_queryset.exists():    print("There is at least one object in some_queryset")

update(**kwargs)
对指定的字段执行SQL更新查询,并返回匹配的行数(如果某些行已具有新值,则可能不等于已更新的行数)。
update()方法立即应用,对更新的QuerySet的唯一限制是它只能更新模型主表中的列,而不是相关模型。你不能这样做,例如:

>>> Entry.objects.update(blog__name='foo') # Won't work!

如果你只是更新一个记录,不需要对模型对象做任何事情,最有效的方法是调用update(),而不是将模型对象加载到内存中。例如,而不是这样做:

e = Entry.objects.get(id=10)e.comments_on = Falsee.save()

应该这样:

Entry.objects.filter(id=10).update(comments_on=False)

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字,任何具有指向要删除的对象的外键的对象将与它们一起被删除。
此级联行为可通过ForeignKey的on_delete参数自定义。

as_manager()
类方法,返回Manager的实例与QuerySet的方法的副本。

4.字段查找

exact
精确匹配。如果为比较提供的值为None,它将被解释为SQL NULL(有关详细信息,请参阅isnull)。
例子:

Entry.objects.get(id__exact=14)Entry.objects.get(id__exact=None)

SQL等价物

SELECT ... WHERE id = 14;SELECT ... WHERE id IS NULL;

iexact
不区分大小写的精确匹配。

contains
区分大小写的敏感字母包含查询。

icontains

in
在给定的列表(元素可以是对象)

gt
大于

gte
大于或等于

It
小于

Ite
小于或等于

startwith
区分大小写,从开始位置匹配

istartwith
不区分大小写,从开始位置匹配

endswith
区分大小写

iendswith
不区分大小写。

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

year
对于日期和日期时间字段,确切的年匹配。整数年

month
对于日期和日期时间字段,确切的月份匹配。取整数1(1月)至12(12月)

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

week_day
对于日期和日期时间字段,“星期几”匹配。
取整数值,表示星期几从1(星期日)到7(星期六)。

hour
对于日期时间字段,精确的小时匹配。取0和23之间的整数

minute
于日期时间字段,精确的分钟匹配。取0和59之间的整数

second
对于datetime字段,精确的第二个匹配。取0和59之间的整数

isnull
值为 True 或 False, 相当于 SQL语句IS NULL和IS NOT NULL.

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

regex
区分大小写的正则表达式匹配。
正则表达式语法是正在使用的数据库后端的语法。在SQLite没有内置正则表达式支持的情况下,此功能由(Python)用户定义的REGEXP函数提供,因此正则表达式语法是Python的re模块。
例:

Entry.objects.get(title__regex=r'^(An?|The) +')

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

0 0
原创粉丝点击