• Django 查询集API


    本篇将详细介绍查询集的API,它建立在下面模型的基础上:

    from django.db import models
    
    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()
    
        def __str__(self):            
            return self.name
    
    class Author(models.Model):
        name = models.CharField(max_length=200)
        email = models.EmailField()
    
        def __str__(self):             
            return self.name
    
    class Entry(models.Model):
        blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
        headline = models.CharField(max_length=255)
        body_text = models.TextField()
        pub_date = models.DateField()
        mod_date = models.DateField()
        authors = models.ManyToManyField(Author)
        n_comments = models.IntegerField()
        n_pingbacks = models.IntegerField()
        rating = models.IntegerField()
    
        def __str__(self):           
            return self.headline

    一、QuerySet何时被提交

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

    可以使用下列方法对QuerySet提交查询操作:

      ·迭代

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

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

      ·切片

        如果使用切片的”step“参数,Django 将执行数据库查询并返回一个列表。

      ·Pickling/缓存

      ·repr()

      ·len()

        当你对QuerySet调用len()时, 将提交数据库操作。

      ·list()

        对QuerySet调用list()将强制提交操作entry_list = list(Entry.objects.all())

      ·bool()

        测试布尔值,像下面这样:

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

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

    二、QuerySet

      下面是对于QuerySet的正式定义:

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

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

        ordered:如果QuerySet是排好序的则为True,否则为False。

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

    三、返回新QuerySets的API

      以下的方法都将返回一个新的QuerySets。

    方法名作用
    filter() 过滤查询对象。
    exclude() 排除满足条件的对象
    annotate() 使用聚合函数
    order_by() 对查询集进行排序
    reverse() 反向排序
    distinct() 对查询集去重
    values() 返回包含对象具体值的字典的QuerySet
    values_list() 与values()类似,只是返回的是元组而不是字典。
    dates() 根据日期获取查询集
    datetimes() 根据时间获取查询集
    none() 创建空的查询集
    all() 获取所有的对象
    union() 并集
    intersection() 交集
    difference() 差集
    select_related() 附带查询关联对象
    prefetch_related()
    预先查询
    extra() 附加SQL查询
    defer() 不加载指定字段
    only() 只加载指定的字段
    using() 选择数据库
    select_for_update()
    锁住选择的对象,直到事务结束。
    raw() 接收一个原始的SQL查询

      1.filter()

        filter(**kwargs)

        返回满足查询参数的对象集合

        查找的参数(**kwargs)应该满足下文字段查找中的格式。多个参数之间是AND关系。

      2.exclude()

        exclude(**kwargs)

        返回一个新的QuerySet,它包含不满足给定的查找参数的对象。

        查找的参数应该满足下文字段查找中的格式。多个参数通过AND连接,然后所有的内容放入NOT()中。 

        下面的示例排除了所有pub_date晚于2005-1-3或者headline为“Hello”的记录:

    Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

      3.order_by()

        order_by(*fields)

        默认情况下,根据模型的Meta类中的ordering属性对QuerySet中的对象进行排序

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

        上面的结果将按照pub_date降序排序,然后再按照headline升序排序。"-pub_date"前面的负号表示降序顺序。 升序是默认的。 要随机排序,使用"?",如下所示:

    Entry.objects.order_by('?')

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

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

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

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

    Entry.objects.order_by('blog')

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

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

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

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

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

      4.reverse()

        reverse()

        反向排序QuerySet中返回的元素。 

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

    my_queryset.reverse()[:5]

        这与Python直接使用负索引有点不一样。 Django不支持负索引,只能曲线救国。

      5.distinct()

        distinct(*fields)

        去除查询结果中重复的行。

        默认情况下,QuerySet不会去除重复的行。当查询跨越多张表的数据时,QuerySet可能得到重复的结果,这时候可以使用distinct()进行去重。

      6.values()

        values(fields, *expressions)

        返回一个包含数据的字典的queryset,而不是模型实例。

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

        下面的例子将values() 与普通的模型对象进行比较:

    # 列表中包含的是Blog对象
    >>> Blog.objects.filter(name__startswith='Beatles')
    <QuerySet [<Blog: Beatles Blog>]>
    # 列表中包含的是数据字典
    >>> Blog.objects.filter(name__startswith='Beatles').values()
    <QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

        该方法接收可选的位置参数*fields,它指定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'}]>

        在values()子句中的聚合应用于相同values()子句中的其他参数之前。 如果需要按另一个值分组,请将其添加到较早的values()子句中。 像这样:

    >>> from django.db.models import Count
    >>> Blog.objects.values('author', entries=Count('entry'))
    <QuerySet [{'author': 1, 'entries': 20}, {'author': 1, 'entries': 13}]>
    >>> Blog.objects.values('author').annotate(entries=Count('entry'))
    <QuerySet [{'author': 1, 'entries': 33}]>

        注意:

        如果有一个字段foo是一个ForeignKey,默认的foo_id参数返回的字典中将有一个叫做foo 的键,因为这是保存实际值的那个隐藏的模型属性的名称。 当调用foo_id并传递字段的名称,传递foo 或values()都可以,得到的结果是相同的。像这样:

    >>> Entry.objects.values()
    <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
    >>> Entry.objects.values('blog')
    <QuerySet [{'blog': 1}, ...]>
    >>> Entry.objects.values('blog_id')
    <QuerySet [{'blog_id': 1}, ...]>

        当values()与distinct()一起使用时,注意排序可能影响最终的结果。

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

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

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

    >>> Blog.objects.values('name', 'entry__headline')
    <QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
         {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>

      7.union()

        union(*other_qs, all=False)

        集合中并集的概念!

        使用SQL的UNION运算符组合两个或更多个QuerySet的结果。例如:

    >>> qs1.union(qs2, qs3)   

        默认情况下,UNION操作符仅选择不同的值。 要允许重复值,请使用all=True参数。

      8.intersection()

        intersection(*other_qs)

        集合中交集的概念!

        使用SQL的INTERSECT运算符返回两个或更多个QuerySet的共有元素。例如:

    >>> qs1.intersection(qs2, qs3)

      9.difference()

        difference(*other_qs)

        集合中差集的概念!

        使用SQL的EXCEPT运算符只保留QuerySet中的元素,但不保留其他QuerySet中的元素。例如:

    >>> qs1.difference(qs2, qs3)
  • 相关阅读:
    [Laravel] mac下通过 homestead 搭建环境 到运行项目
    Mac下Laravel的Homestead环境配置
    Window10 下安装 Laravel / Homestead 视频
    Windows 10下Laravel的开发环境安装及部署(Vagrant + Homestead)
    Apache 调用不同的 PHP 版本
    inux系统用户名和全名有什么区别
    oracle 学习day01
    rpm
    Linux下可以使用ps命令来查看Oracle相关的进程
    oracle 建用户
  • 原文地址:https://www.cnblogs.com/lavender1221/p/12518896.html
Copyright © 2020-2023  润新知