QuerySet何时被提交

在内部,创建、过滤、切片和传递一个QuerySet不会真正的操作数据库,在对QuerySet提交前,不会发生任何实际的数据库操作。
以下方法会对QuerySet提交查询操作:

  • 迭代
    QuerySet是一个可迭代对象,在首次迭代查询集时执行实际的数据库查询。
    for e in Entry.objects.all():
      print(e)
    
  • 使用带有步长的切片操作,Django将会执行数据库查询,并放回一个列表。
  • pickling / Caching
  • repr()
  • len(),返回结果列表的长度,可以使用count()方法代替此操作。
  • list(),对QuerySet调用list()将强制提交操作。
  • bool(),如果只想确定是否存在至少一个结果(并不需要实际对象),建议使用exists()方法。

QuerySet

class QuerySet(model=None, query=None, using=None)
QuerySet类有两个公有属性:

  • ordered
    如果QuerySet是排好序的为True,否则为False。
  • db
    如果现在执行此查询,将使用的数据库。

返回新的QuerySet的API

1.filter()

filter(**kwargs),过滤筛选对象。
返回QuerySet包含与给定查找参数匹配的新对象。

2.exclude()

exclude(**kwargs),排除满足条件的对象。
返回QuerySet包含与给定查找参数不匹配的新对象。

3.annotate()

annotate(arg, **kwargs),使用聚合函数。
表达式可以是简单的值,对模型上的字段的引用或者聚合表达式。annotate()的每个参数都是一个annotation,它将添加到返回的QuerySet每个对象中。
关键字参数指定的annotation将使用关键字作为annotation的别名。匿名参数的别名将基于聚合函数的名称和模型的字段生成。只有引用单个字段的聚合表达式才可以使用匿名参数,其他所有形式都必须使用关键字参数。

from django.db.models import Count
q = Blog.objects.annotate(Count("entry"))
q[0].name   # 显示第一篇博客的名字
q[0].entry__name  # 第一篇博客的条目数

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

q = Blog.objects.annotate(number_of_entries=Count("entry"))
q[0].number_of_entries  # 使用提供的名称获取第一个博客上的条目数

4.order_by()

order_by(*fields),对QuerySet进行排序。
默认情况下,Django会根据模型元类中ordering属性对QuerySet对象进行排序。

Entry.objects.filter(pub_date__year=2005).order_by("-pub_date", "headline")  # 先将结果按pub_date降序排序,然后按headline升序排序。

关键字前面带有符号”-“表示为降序排序。如果要使用随机排序,需要使用order_by(“?”)。例如:Entry.objects.order_by("?")
使用order_by(“?”)将会非常耗费资源而且速度很慢,具体取决于使用的数据库。
如果要按另一个模型中的字段进行排序,可以使用查询关联模型对的语法。

Entry.objects.order("blog__name", "headline")

如果排序的字段与另一个模型关联,Django将使用关联的模型的默认排序,如果没有模型元类的ordering没有指定属性,那么将通过关联模型的主键进行排序。

# 没有设置ordering属性,下面两个排序是等效的
Entry.objects.order_by("blog")
Entry.objects.order_by("blog_id")

# 如果设置ordering = name,下面两个排序是等效的
Entry.objects.order_by("blog")
Entry.objects.order_by("blog_name")

也可以通过调用表达式的desc()或者asc()方法:

Entry.objects.order_by(Coalesce("summary", "headline").desc())

没有方法指定排序是否考虑大小写,对于大小写的敏感性,Django将根据数据库中的排序方式排序结果。可以通过Lower将一个字段转换为小写来排序,它将达到大小写一致的排序:

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

可以通过检查QuerySet.ordered属性来判断查询是否是排序的。
每次order_by()都将清楚前面的任何排序。

Entry.objects.order_by("headline").order_by("pub_date")  # 将以pud_date字段进行排序

5.reverse()

反向排序QuerySet中返回的元素,第二次调用将恢复到原有的排序。

# 获取QuerySet中最后五个元素
QuerySet.reverse()[:5]

6.distinct()

distinct(*fileds),去除查询结果中重复的行。
注意,order_by()调用中使用的任何字段都含在SQL SELECT列中。当与distinct()结合使用时,有时可能会导致意外结果。如果从相关模型中按字段排序,这些字段将被添加到所以选列中,并且它们可能使重复的行看起来是不同的。由于额外的列不会出现在返回的结果中(它们只是为了支持排序),所以有时看起来返回的结果并不明显。在使用distinct(),请小心按相关模型排序。
类似的,如果使用values()查询来限制所选择的列,那么任何order_by()(或默认模型排序)中使用队列仍然会涉及,并且可能影响结果的唯一性。当同时使用distinct()和values()时,在按照values()调用中没有的字段排序时也要小心。

不是所有的数据库引擎都支持distinct中参入字段参数,只有PostgreSQL支持。

7.values()

values(field, *expressions),返回一个包含数据的字段的QuerySet,而不是模型实例。其中,每一个字段表示一个对象。

# values()与模型对象比较
Blog.objects.filter(name__startswith="Beatles")  # <QuerySet [<Blog: Beatles Blog>]>

Blog.objects.filter(name__startswith="Beatles").values()  # <QuerySet [{"id": 1, "name": "beatles blog"}]>

该方法接受可选的位置参数*fileds,它将指定values()将显示哪些字段。如果指定字段,每个字典中只会包含指定字段的键值对。如果没有指定,每个字典中将包含数据库种所有字段的键值对。

Blog.objects.values()  # <QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
Blog.objects.values('id', 'name')  # <QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

values()方法还有关键字参数**expressions,它们将被传递给annotate()。

from django.db.models.functions import Lower
Blog.objects.values(lower_name=Lower('name'))  # <QuerySet [{'lower_name': 'beatles blog'}]>

8.values_list()

values_list(*fileds, flat=False),与values()类似,但是返回的是一个元组而不是字段。每个元组中包含传递给values_list()调用的相应字段和表达式的值。

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

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

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

9.dates()

dates(field, kind, order="ASC"),返回一个QuerySet,表示QuerySet内容中特定类型的所有可用日期的datetime.date对象列表。

  • field:模型的DateField的名称。
  • kind:应为”year”、”month”、”week”(适用于Django2.1以上)或”day”。结果列表中的每个datetime.date对象被截取为给定的类型。
    • year:返回该字段的所有不同年份值的列表。
    • month:返回该字段的所有不同年/月值的列表。
    • week:返回该字段的所有不同年/周值的列表。
    • day:返回该字段的所有不同年/月/日值得列表。
  • order,默认为”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', 'week')
    [datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
    >>> 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)]
    

    10.datetimes()

    datetimes(field_name, kind, order="ASC", tzinfo=None)
    返回一个QuerySet,为datetime.datetime对象的列表,表示QuerySet内容红特定种类的所有可用日期。
  • field_name:DateTimeField的名称。
  • kind:参数可以是”year”、”month”、”week”(适用于Django2.1以上)、”day”、”hour”、”minute”或”second”。
  • order:默认为”ASC”,也可以为”DESC”。它指定结果如何排序。
  • tzinfo:定义在截取之前将数据时间转换到的时区。

    11.none()

    创建空查询集。调用none()将创建一个不返回任何对象的查询集,并且在访问结果时不会执行任何查询。
    >>> Entry.objects.none()
    <QuerySet []>
    >>> from django.db.models.query import EmptyQuerySet
    >>> isinstance(Entry.objects.none(), EmptyQuerySet)
    True
    

    12.all()

    获取所有对象。select_related(*field),沿着外键关系查询关联的对象的数据。
    这会生成一个复杂的查询,并引起性能的虽好,但是在以后使用外键关系时,将不需要再次查询数据库。
    在传递给select_related()的字段中,可以使用任何ForeignKey和OneToOneField。prefetch_related(*lookups),在单个批处理中自动检索每个指定查找的相关对象。
    示例:
    ```python
    from django.db import models

class Topping(models.Model):
name = models.CharField(max_length=30)

class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)

def __str__(self):
    return "%s (%s)" % (
        self.name,
        ", ".join(topping.name for topping in self.toppings.all()),
    )
并运行:
```python
>>> Pizza.objects.all()
["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...

问题在于每次QuerySet要求Pizza.objects.all()查询数据库,因此self.toppings.all()将在Pizza Pizza.__str__()中的每个项目的Toppings表上运行查询。
可以使用prefetch_related减少为只有两个查询:

>>> Pizza.objects.all().prefetch_related('toppings')

意味着,现在每次self.toppings.all()被调用,不会再去数据库查找,而是在一个预取的QuerySet缓存中查找。

15.extra()

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
有些情况下,Django的查询语法难以简单的表达复杂的WHERE子句,对于这种情况,可以在extra()生成的SQL从句中注入新自居。
使用extra()应谨慎,每次使用时,都应该转义用户可以通过使用params控制的任何参数,以防止SQL注入攻击。

16.defer()

defer(*fields),不加载指定字段。
在一些复杂的数据建模情况下,模型可能包含大量字段,其中一些可能包含大尺寸数据,将它们转换为Python对象需要花费很大的代价。
具有延迟加载字段的查询集仍将返回模型实例,每个延迟字段将在访问该再短时从数据库中检索。defer()可以多次调用,每次调用都会向延迟集添加新字段。
如果要清楚延迟字段集,需将None作为参数传递到defer()。

17.only()

only(*fields),只加载指定字段。
每当你调用only()方法时,它都将替换立即加载的字段集。所以,对于连续调用only()方法的结果是只有最后一only()会被真正调用。
only()方法和defer()方法为数据加载提供了优化方法。

18.using()

using(alias),指定在哪个数据库上查询QuerySet。

19.select_for_update()

select_for_update(nowait=False, skip_locked=False),返回一个锁住行直到事务结束的查询集。
调用此方法时,所有匹配的行都将被锁定,直到事务结束。可以通过锁防止数据被其他事务修改。

20.raw()

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

不返回QuerySet的API

1.get()

get(**kwargs),返回按照查询参数匹配到的单个对象,参数的格式应该符合Field lookups的要求。
如果根据查询条件没有找到匹配的对象,将抛出DoesNotExist异常;如果匹配到的对象个数不只一个,将抛出MultipleObjectsReturned异常。

2.create()

create(**kwargs),一步操作中同时创建并保存对象的便捷方式。

3.get_or_create()

get_or_create(defaults=None, **kwargs),通过**kwargs查询,如果该对象不存在将创建一个新对象。
该方法将会返回要一个元组(object, created),object表示查询到或新创建的对象,created表示该对象是否是新创建的,为一个布尔值。

4.update_or_create()

update_or_create(defaults=None, **kwargs),通过**kwargs更新对象,如果该对象不存在将创建一个新对象。
batch_size:参数控制在单个查询中创建的对象数。

5.bulk_create()

bulk_create(objs, batch_size=None),以高效的方式(通常只有一个查询)将提供的对象列表插入到数据库中。
注意:

  1. 不会调用模型的save()方法,并且不会发送pre_save和post_save信号。
  2. 不适用于多表继承场景中的子模型。
  3. 如果模型的主键是AutoField,则不会像save()那样检索并设置主键属性,除非数据库后端支持。
  4. 不适用于多对多关系。

    6.count()

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

    7.in_bulk()

    in_bulk(id_list=None),获取主键值的列表,并返回将每个主键值映射到具有给定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([])
    {}
    >>> Blog.objects.in_bulk()
    {1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
    

    8.iterator()

    提交数据库操作,获取QuerySet,并返回一个迭代器。

    9.latest()

    latest(field_name=None),使用日期字段field_name,按日期返回最新对象。

    10.earliest()

    earliest(field_name=None),使用日期字段field_name,按日期返回最早对象。

    11.first()

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

    12.last()

    返回结果集的最后一个对象,如果没有找到时返回None。如果QuerySet没有设置排序,则将按主键进行排序。

    13.arrgregate()

    aggregate(args, *kwargs),返回汇总值的字典(平均值,总和等),通过QuerySet进行计算。每个参数指定返回的字典中将要包含的值。
    使用关键字参数指定的聚合将使用关键字参数的名称作为Annotation 的名称。 匿名参数的名称将基于聚合函数的名称和模型字段生成。 复杂的聚合不可以使用匿名参数,必须指定一个关键字参数作为别名。

    14.exists()

    用于判断QuerySet是否存在,如果存在返回True,不存在返回False。

    15.update()

    update(**kwargs),对指定的字段执行批量更新操作,并返回匹配的行数。

    16.delete()

    批量删除QuerySet中的所有对象,并返回删除的对象个数和每个对象类型的删除次数的字典。
0条评论

相关推荐

django教程

r

Django 2019-05-20 10:53:53

Celery

celery学习资料

Django 2019-05-25 18:41:55

Django-rest-framework教程

django-rest-framework教程。

Django 2019-07-18 16:33:26

django实用资料

django项目从0到1自己总结的实用的资料,大部分常用的功能这里都有

Django 2019-05-08 18:21:34