• Django的model操作中一些常用的小点


    一、django的orm的13种基本的查询方法

    1、all方法,查询某张表中的所有的数据

    user_obj_list = models.Person.objects.all()
    

      

    返回的结果是queryset对象,也就是一个对象的集合

    <QuerySet [<Person: 人的对象小黑9>, <Person: 人的对象小黑8>, <Person: 人的对象小黑7>, <Person: 人的对象小黑6>, <Person: 人的对象小黑5>, <Person: 人的对象小黑4>, <Person: 人的对象小黑3>, <Person: 人的对象小黑2>, <
    Person: 人的对象小黑19>, <Person: 人的对象小黑18>, <Person: 人的对象小黑17>, <Person: 人的对象小黑16>, <Person: 人的对象小黑15>, <Person: 人的对象小黑14>, <Person: 人的对象小黑13>, <Person: 人的对象小黑12>, <Pers
    on: 人的对象小黑11>, <Person: 人的对象小黑10>, <Person: 人的对象小黑1>, <Person: 人的对象小黑0>]>
    

      

    2、filter方法,查询符合某个条件的所有的数据

    user_objs = models.Person.objects.filter(name="小黑7")

    返回的结果也是一个queryset对象,也就是一个对象的集合

    <QuerySet [<Person: 人的对象小黑7>]>
    

      

    3、get方法,返回的单个对象

    user_obj = models.Person.objects.get(name="小黑7")
    

      

    返回的是单个对象

    人的对象小黑7
    

      

    # 返回的时候某一个具体的对象,如果这个条件的对象不存在,会报错

    4、exclude方法,对条件取反

    user_obj = models.Person.objects.exclude(id__gte=4)
    

      

    返回的是一个queryset对象的

    exclude方法 <QuerySet [<Person: 人的对象小黑2>, <Person: 人的对象小黑1>, <Person: 人的对象小黑0>]>
    

      

    5、values方法,查询一个queryset对象的值

    user_obj = models.Person.objects.exclude(id__gte=4).values("id","name","birthday_1")
    

      

    返回的是一个一个queryset的对象集合,是一个大的列表,每个列表的元素又是每个对象的小字典

    <QuerySet [{'id': 3, 'name': '小黑2', 'birthday_1': datetime.datetime(2016, 12, 6, 0, 0)}, {'id': 2, 'name': '小黑1', 'birthday_1': datetime.datetime(2016, 5, 13, 0, 0)}, {'id': 1, 'name': '小黑0', 'birthday_1':
    datetime.datetime(2016, 3, 5, 0, 0)}]>
    

      

    6、values_list,查询一个queryset对象的值

    user_obj = models.Person.objects.exclude(id__gte=4).values_list("id", "name", "birthday_1")
    

      

    返回的是一个queryset对象,这个对象是一个列表,列表中的每个元素是每个对象的元组信息

    <QuerySet [(3, '小黑2', datetime.datetime(2016, 12, 6, 0, 0)), (2, '小黑1', datetime.datetime(2016, 5, 13, 0, 0)), (1, '小黑0', datetime.datetime(2016, 3, 5, 0, 0))]>
    

      

    7、order_by,根据某个字段排序,如果字段加一个负号,则是逆序排序,如果不加,则则是正序排列

    user_obj = models.Person.objects.exclude(id__gte=4).order_by("-id")
    

      

    返回的结果也是一个queryset对象

    <QuerySet [<Person: 人的对象小黑2>, <Person: 人的对象小黑1>, <Person: 人的对象小黑0>]>
    

      

    user_obj = models.Person.objects.exclude(id__gte=4).order_by("id")
    

      

    返回的结果也是一个queryset对象

    <QuerySet [<Person: 人的对象小黑0>, <Person: 人的对象小黑1>, <Person: 人的对象小黑2>]>
    

      

    8、reverse方法,对一个有序的queryset对象,做反转操作

    user_obj = models.Person.objects.exclude(id__gte=4).order_by("-id").reverse()
    

      

    返回的结果

    <QuerySet [<Person: 人的对象小黑0>, <Person: 人的对象小黑1>, <Person: 人的对象小黑2>]>
    

      

    9、distance方法,对返回的数据去重,在外键中用的比较多

    10、count方法,统计查询到的数据的个数

    11、first方法,在queryset对象中返回查询到的第一条数据

     

    12、last方法,在queryset对象中返回查询到的最后一条数据

     

    13、exists方法,判断用指定的过滤条件查询是否有值

    二、单表查询中的双下划线查询

    _exact 精确等于 like 'aaa'
     
     __iexact 精确等于 忽略大小写 ilike 'aaa'
     
     __contains 包含 like '%aaa%'
     
     __icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。
     
    __gt 大于
     
    __gte 大于等于
     
    __lt 小于
     
    __lte 小于等于
     
    __in 存在于一个list范围内
     
    __startswith 以...开头
     
    __istartswith 以...开头 忽略大小写
     
    __endswith 以...结尾
     
    __iendswith 以...结尾,忽略大小写
     
    __range 在...范围内
     
    __year 日期字段的年份
     
    __month 日期字段的月份
     
    __day 日期字段的日
     
    __isnull=True/False
     
     
    例子:
     
    >> q1 = Entry.objects.filter(headline__startswith="What")
     
    >> q2 = q1.exclude(pub_date__gte=datetime.date.today())
     
    >> q3 = q1.filter(pub_date__gte=datetime.date.today())
     
    >>> q = q.filter(pub_date__lte=datetime.date.today())
     
    >>> q = q.exclude(body_text__icontains="food")
    

      

        models.test_orm.objects.filter(id__in=[12,34,21])
        models.test_orm.objects.filter(id__gt=12)
        models.test_orm.objects.filter(name__icontains="aaaa")
        models.test_orm.objects.filter(name__iendswith="aaa")
    

      

     三、一对多的查询

    1、先看正向查询,有两种方式,方式1,先在多表中找到某个对象,然后通过外键的字段找到一表中的对象

        book_obj = models.Book.objects.all().last()
    
        print(book_obj.book_publish)
    
        print(book_obj.book_publish.name)
    

      

    2、正向查询的方式2,在values和values_list中利用外键字段的双下划线进行跨表查询

        # 通过双下划线在values中进行跨表查询,需要通过外键的字段
        publist_obj = models.Book.objects.filter(id=3).values("id","book_name","book_publish","book_publish__name")
    
        print(publist_obj)
    
        # 通过双下划线在values_list中进行跨表查询,需要通过外键的字段
        publist_obj = models.Book.objects.filter(id=3).values_list("id","book_name","book_publish","book_publish__name")
    
        print(publist_obj)
    

      

    3、在看反向查询

    我们先来介绍一下外键中的related_name字段,如果,如果设置了这个值,则反向查询的时候用related_name的值,如果没有设置这个值,则通过“多表的名称_set”进行反向查询

    首先我们看下不设置related_name的反向查询

    首先外键是这样设置的

        book_publish = models.ForeignKey(to="Publisher")
    

      

    然后进行反向查询,这里要记住,如果使用values或者values_list方法,则里面的参数和正向查询是一样的

        publist_obj = models.Publisher.objects.all().first()
    
        print(publist_obj.book_set.all())
        print(publist_obj.book_set.values_list("id","book_name","book_publish","book_publish__name"))
    

      

    然后我们在看下在外键中设置related_name的方向查询,下面的例子,我们设置了ralated_name,所以反向查询则要使用PubToBook进行反向查询

    book_publish = models.ForeignKey(to="Publisher", related_name="PubToBook")
    

      

    同样,在values和values_list方法中,则里面的参数和正向查询是一样的

        print(publist_obj.PubToBook.all())
        print(publist_obj.PubToBook.values_list("id", "book_name", "book_publish", "book_publish__name"))
    

      

    这里要注意,如果要调用values和values_list方法,则必须要用queryset对象

    如果要使用点,则必须要单个对象

    四、多对多操作

    1、create操作

        # 1、方法1,create
    
        # 我们的manytomant字段在book表中,我们可以调用book表中的某个对象的create方法,去创建一个auther对象,创建成功后,会自动把这个book对象和
        # 和我们新创建的出版社关联起来
    
    
            # book_obj = models.Book.objects.get(id=2)
    
        # book_obj.book_auther.create(
        #     auther_name = "大学作者10",
        # )
    

      

    2、add操作

        # 2、add方法
        # 1、由于manytomany字段在book表中,我们可以先查到某个或者某几个auther表中的对象,某个book对象通过manytomany字段
        # 为某本书添加和多个auther表的关联,这里还可以传递一个列表对象,则需要用*列表对象传递进去,可以添加一个对象,也可以
        # 添加多个对象,也可以传递一个列表进去
        #
        # auther_1 = models.Auther.objects.all().first()
        # auther_2 = models.Auther.objects.get(id=2)
        #
        # models.Book.objects.all().last().book_auther.add(
        #     auther_1,auther_2
        # )
    
        # add的方法也可以直接传递一个id的值进去
    

      

    3、remove操作

        # 3、remove方法
        # 先在book表中找到某个对象,然后通过多对多字段进行remove操作,删除这个book和作者的关系
    
        # book_obj = models.Book.objects.all().first()
    
    
        # 3_1、可以直接传递一个id进去
        # book_obj.book_auther.remove(11)
    
        # 3_2、传递一个对象进去
    
        # del_auther_obj = models.Auther.objects.get(id=5)
        #
        # book_obj.book_auther.remove(del_auther_obj)
    

      

     4、clear方法

        # 4、clear方法
    
        book_obj = models.Book.objects.all().first()
    
        book_obj.book_auther.clear()
    

      

    五、聚合查询

        from django.db.models import Avg
        from django.db.models import Max
        from django.db.models import Min
        from django.db.models import Sum
    

      

        ret = models.Book.objects.all().aggregate(Sum("book_price"))
        print(ret)
    
        ret = models.Book.objects.all().aggregate(Avg("book_price"))
        print(ret)
    
        ret = models.Book.objects.all().aggregate(Max("book_price"))
        print(ret)
    
        ret = models.Book.objects.all().aggregate(Min("book_price"))
        print(ret)
    

      

    结果如下

    {'book_price__sum': Decimal('468.98')}
    {'book_price__avg': 46.898}
    {'book_price__max': Decimal('99.43')}
    {'book_price__min': Decimal('14.43')}
    

      

    六、分组查询

        from django.db.models import Avg
        from django.db.models import Max
        from django.db.models import Min
        from django.db.models import Sum
    

      

    先通过values方法进行分组,然后求每个分组下的最大值,平均值,最小值,和,通过表中的所有字段都可以做分组查询

        ret = models.Book.objects.all().values("book_publish").annotate(Sum("book_price"))
        print(ret)
    
        ret = models.Book.objects.all().values("book_auther").annotate(Min("book_price"))
        print(ret)
    
        ret = models.Book.objects.all().values("book_name").annotate(Max("book_price"))
        print(ret)
    

      

    结果

    <QuerySet [{'book_publish': 10, 'book_price__sum': Decimal('102.93')}, {'book_publish': 15, 'book_price__sum': Decimal('88.86')}, {'book_publish': 16, 'book_price__sum': Decimal('48.84')}, {'book_publish': 17, 'bo
    ok_price__sum': Decimal('34.49')}, {'book_publish': 18, 'book_price__sum': Decimal('99.43')}, {'book_publish': 19, 'book_price__sum': Decimal('94.43')}]>
    <QuerySet [{'book_auther': None, 'book_price__min': Decimal('34.23')}, {'book_auther': 1, 'book_price__min': Decimal('14.43')}, {'book_auther': 2, 'book_price__min': Decimal('34.41')}, {'book_auther': 3, 'book_pri
    ce__min': Decimal('14.43')}, {'book_auther': 4, 'book_price__min': Decimal('32.43')}, {'book_auther': 7, 'book_price__min': Decimal('34.49')}, {'book_auther': 8, 'book_price__min': Decimal('56.43')}, {'book_auther
    ': 9, 'book_price__min': Decimal('94.43')}, {'book_auther': 10, 'book_price__min': Decimal('94.43')}]>
    <QuerySet [{'book_name': '大学体育1', 'book_price__max': Decimal('34.23')}, {'book_name': '大学体育2', 'book_price__max': Decimal('56.43')}, {'book_name': '跟周雍博学玩游戏', 'book_price__max': Decimal('14.43')},
    {'book_name': '跟妈妈学做饭', 'book_price__max': Decimal('34.47')}, {'book_name': '跟小妹学哭鼻子', 'book_price__max': Decimal('34.49')}, {'book_name': '跟崔洪艳学会计', 'book_price__max': Decimal('34.41')}, {'boo
    k_name': '跟崔皓然学爬楼梯', 'book_price__max': Decimal('32.43')},, {'book_name': '跟爷爷学木匠', 'book_price__max': Decimal('94.43')}, {'book
    _name': '跟爸爸学开车', 'book_price__max': Decimal('34.23')}]>
    

      

     分组查询的高级用法,求每个作者出的book的总价格

       ret = models.Auther.objects.all().annotate(book_price_sum=Sum("book__book_price")).values_list("auther_name","book_price_sum")
        print(ret)
    

      

    结果如下

    <QuerySet [('大学作者0', Decimal('266.42')), ('大学作者1', Decimal('133.84')), ('大学作者2', Decimal('83.31')), ('大学作者3', Decimal('200.50')), ('大学作者4', None), ('大学作者5', None), ('大学作者6', Decimal('12
    8.92')), ('大学作者7', Decimal('56.43')), ('大学作者8', Decimal('94.43')), ('大学作者9', Decimal('94.43')), ('大学作者10', None)]>
    

      

    下面来解释一下上面的代码

    先拿到所有的作者,然后求出每个作者的书的总价格,然后赋值给一个变量book_price_sum,赋值给的这个变量后,也就是在数据库中会临时多一个字段,这个字段就是book_price_sum,然后通过values_list方法打印出作者名称和book_price_sum的值,由于作者表中没有manytomany字段,需要用表明+下划线的方法做跨表查询

    下面这段代码更好理解,实现的效果和上面的一样

        ret = models.Auther.objects.all().values("auther_name").annotate(book_price_sum=Sum("book__book_price")).values_list("auther_name",
                                                                                                       "book_price_sum")
        print(ret)
    

      

    7、F查询

       from django.db.models import F
        from django.db.models import Q
    
    
        # 当我们需要对表中的 数字字段做比较或者操作的时候加减乘除等数学运算的时候可以用到F查询
    
        print("F查询".center(100,"*"))
    
        # 过滤出来kucun字段大于卖出字段的值
        ret = models.Book.objects.filter(kucun__gt=F("maichu"))
        print(ret)
    
        # 为库存字段+2
        models.Book.objects.all().update(kucun=F("kucun")+2)
    

      

    8、Q查询

     append的方法需要传递一个tuple

       q_obj = Q()
    
        q1 = Q()
        q2 = Q()
    
        q1.connector = "AND"
    
        q1.children.append(("id__gte",3))
      
        q1.children.append(("kucun__gte",1000))
    
        q2.connector = "OR"
    
        q2.children.append(("maichu__lte",3000))
    
    
        q_obj.add(q1,"AND")
        q_obj.add(q2,"AND")
    
        # 过滤条件1:id大于等于3,库存大于等于1000的,两个条件是AND的关系
        # 过滤条件2:卖出小于等于3000的,如果在q2中继续添加条件,他是or的关系
        # 最后过滤条件1和过滤条件2是AND的关系
        
    
        ret = models.Book.objects.filter(q_obj).values("id","kucun","maichu")
        print(ret)
    

      

    结果如下

    <QuerySet [{'id': 4, 'kucun': 1012, 'maichu': 299}, {'id': 9, 'kucun': 4010, 'maichu': 19}]>
    

      

     9、一对一操作

    我们可以把一张表中不常用的字段,或者不重要的字段放在另外一张表中,比如我们通过qq去登录第三方的网站,这个时候就可以把一些不重要的字段暴露给第三方网站,而不用把很重要的信息暴漏给第三方网站

    先看下我们设计的表

    class partent(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        details = models.OneToOneField(to="details_info",related_name="reverse_look_partent")
    
        class Meta:
            unique_together = ("name","pwd")
    
    
        def __str__(self):
            return self.name
    
    
    class details_info(models.Model):
        sex = models.CharField(max_length=32)
        addr = models.CharField(max_length=64,null=True)
        phone = models.PositiveIntegerField(unique=True)
    
        def __str__(self):
            return self.phone
    

      

    如果我们要给表中增加数据,则需要先给details_info表中插入数据,然后在为parent表中插入数据

    为details_info表中插入数据

        import random
        for i in range(5):
            models.details_info.objects.create(
                sex = "man",
                addr = "深圳" + str(random.randint(1,10000)),
                phone = random.randint(100000000,900000000)
            )
    

      

    在为parent表中插入数据

        for i in models.details_info.objects.all().values_list("id"):
    
            models.partent.objects.create(
                name = "小黑" + str(i[0]),
                pwd = "password" + str(random.randint(100000000,900000000)),
                details_id = int(i[0]),
    
            )
    

      

    最后我们看下一对一的正向和反向查询

    分别验证通过对象和query_set对象进行查询

        p_obj = models.partent.objects.all().last()
    
        print("一对一的正向查询1",p_obj.details.phone)
    
        i = models.partent.objects.all().first().id
    
    
        p_obj = models.partent.objects.filter(id=i)
    
        print("一对一的正向查询2",p_obj.values("id","name","details__phone"))
    

      

    在看下反向查询

        d_obj = models.details_info.objects.all().first()
    
        print("一对一的反向查询1",d_obj.reverse_look_partent.name)
    
        i = models.details_info.objects.all().last().id
    
        d_obj = models.details_info.objects.filter(id=i)
    
        print("一对一的反向查询2",d_obj.values("reverse_look_partent__id","reverse_look_partent__name","reverse_look_partent__pwd","sex","addr","phone"))
    

      

    我们重点看下通过query_set对象进行反向查询这里

    10、多对多的其他方式,手动创建第三张表的方式,之前学的时候由django为我们创建的第三张表,下面我们我们介绍下由我们自己创建第三张表时间多对多的方式

    先看下数据库的表结构,用两个外键来实现多对多

    class Student(models.Model):
        name = models.CharField(max_length=64)
        age = models.PositiveSmallIntegerField()
    
        class Meta:
            unique_together = ("name","age")
    
        def __str__(self):
            return self.name
    
    
    
    class Role(models.Model):
        role_name = models.CharField(max_length=63,unique=True)
    
        def __str__(self):
            return self.role_name
    
    
    class Student2Role(models.Model):
        to_student = models.ForeignKey(to="Student")
        to_role = models.ForeignKey(to="Role")
    

      

    如果要进行跨表查询,只能去第三张表通过表名去查询

    def manytomany(request):
        ret = models.Student2Role.objects.filter(to_student_id=1).values_list("to_role")
    
        print(ret)
    
        ret = [i[0] for i in ret]
    
        ret = models.Role.objects.filter(id__in=ret).values_list("role_name")
        print(ret)
    
    
    
        return HttpResponse("manytomany")
    

      

  • 相关阅读:
    live 555 freebsd 或centos 7.4 实现代理视频直播服务
    [教学] Log.d 日志调试查看(所有平台)
    [示例] 使用 TStopwatch 计时
    [安裝] Ubuntu Server 初试
    [改善] dcef3 for Firemonkey 浏览器控件,拉动窗体大小会闪烁的问题
    [示例] Drag And Drop for FireMonkey (Win & macOS)
    [原创] 改善 Firemonkey Canvas 几何绘图质量问题(移动平台)
    [示例] Firemonkey 画出 1 点像素的线
    [修正] Firemonkey TFrame 存档后,下次载入某些事件连结会消失(但源码还在)
    [问答] Firemonkey 控件继承后无法显示(空白)
  • 原文地址:https://www.cnblogs.com/bainianminguo/p/9678408.html
Copyright © 2020-2023  润新知