• ORM关联表模型


    ORM关联表模型

    一、创建表

    1.一对一:

    1 class Author(models.Model):
    2     nid = models.AutoField(primary_key=True)
    3     name=models.CharField( max_length=32)
    4     age=models.IntegerField()
    5 
    6     # 与AuthorDetail建立一对一的关系,外键随便在哪一方
    7     authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)  #生成一对一或一对多的外键时必须加on_delete=models.CASCADE
    8     #注意!!!必写:on_delete=models.CASCADE:删除关联数据,与之关联也删除

    2.一对多:

    1 class Book(models.Model):
    2 
    3     nid = models.AutoField(primary_key=True)
    4     title = models.CharField( max_length=32)
    5     publishDate=models.DateField()
    6     price=models.DecimalField(max_digits=5,decimal_places=2)
    7 
    8     # 与Publish建立一对多的关系,外键字段建立在多的一方(多的一方对应少的一个)
    9     publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)

    3.多对多:

     1 class Book(models.Model):
     2 
     3     nid = models.AutoField(primary_key=True)
     4     title = models.CharField( max_length=32)
     5     publishDate=models.DateField()
     6     price=models.DecimalField(max_digits=5,decimal_places=2)
     7 
     8 
     9     # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    10     authors=models.ManyToManyField(to='Author',)

    二、添加表数据:

    1.一对多:

     1    #单表添加记录(没有任何关联)
     2     pub = Publish.objects.create(name="人民出版社", city="北京", email="123@qq.com")
     3 
     4     #为book表绑定关系:publish
     5     #方式一:
     6     book_obj = Book.objects.create(title="红楼梦", publishDate="2018-05-06", price="200", publish_id=1)
     7     print(book_obj.title)  # 返回值book_obj为插入的这条数据的对象
     8     # 方式二:
     9     publish = Publish.objects.filter(nid=1).first()  # 拿到nid=1的queryset,只有加了first才在列表中拿到第一个对象
    10     book_obj = Book.objects.create(title="水浒传", publishDate="2522-01-06", price="500", publish=publish)
    11     print(book_obj.title)  # 返回值book_obj为插入的这条数据的对象
    12     print(book_obj.publish)  # 与这本书关联的出版社的对象:Publish object (1)
    13     print(book_obj.publish_id)  # 打印publish_id
    14     print(book_obj.publish.name)
    15     print(book_obj.publish.city)
    16 
    17     return HttpResponse("OK")

    2.多对多:

     1     '''-----------------------------绑定多对多的关系-------------------------------'''
     2 
     3     #创建数据
     4     book_obj = Book.objects.create(title="金2", publishDate="1920-11-22", price=50, publish_id=2)
     5 
     6     # 为书籍绑定的做作者对象
     7     alex=Author.objects.filter(name="alex").first() # 在Author表中主键为2的纪录
     8     egon=Author.objects.filter(name="egon").first() # 在Author表中主键为1的纪录
     9 
    10 
    11     # 绑定多对多关系,即向关系表book_authors中添加纪录
    12     #pycharm提供的接口找到多对多关系的表,book_obj(添加数据的对象).authors(在创建表类的时候ManytoManyField开的接口).add()
    13     book_obj.authors.add(alex, egon)  # 将某些特定的 model 对象添加到被关联对象集合中。   =======    book_obj.authors.add(*[])
    14     book_obj.authors.add(1,2)  # 可以直接添加主键
    15     book_obj.authors.add(*[1,2,3])  # 给函数添加列表要在前面加*

    3.解除多对多关系:

    1     #解除多对多的关系
    2     #解除的前提:先查到一个数据,找对应数据解除
    3     book_obj = Book.objects.filter(nid=9).first()
    4     # book_obj.authors.remove(2)  # book_obj=9,authors=2,解除关系9-2
    5     #
    6     # book_obj.authors.clear()  # 清空被关联对象集合,只要book_id=4全部清除
    7 
    8     print(book_obj.authors.all())  #类型:queryset 获取所有book_obj关联的作者对象的集合
    9     print(book_obj.authors.all().value("name"))  # 拿到author的名字

    三、跨表查询

    1.基于对象的查询------->子查询

    一对多:

     1     A-B
     2     
     3     正向查询:关联属性在A表中  A--->B
     4     反向查询:关联属性在A表中  B--->A
     5     
     6     
     7     一对多查询:
     8     正向查询按字段
     9     反向查询安表名小写_set.all()
    10     
    11                               (正)book_obj.publish
    12         Book(关联属性:publish)  -------------->   Publish
    13                               (反)book_set.all()  #queryset

    实例:

      (1)一对多正向查询:

    1     #一对多正向查询:查询金这本书的出版社名字
    2 
    3     book_obj = Book.objects.filter(title="").first()
    4     print(book_obj.publish.name)  # 与这本书关联的出版社对象,的名字

      (2)一对多反向查询:

    1     #一对多反向查询:查询人民出版社出版过的书籍名称
    2     publish = Publish.objects.filter(name="人民出版社").first()
    3     print(publish.book_set.all())  # 拿到书籍对象的集合queryset

    多对多:

    1     多对多查询:
    2     正向查询按字段.all()
    3     反向查询安表名小写_set.all()
    4     
    5                               (正)book_obj.authors.all()
    6         Book(关联属性:publish)  ------------------------>   Author
    7                               (反)book_set.all()  #queryset

    实例:

      (1)多对多正向查询:

    1     #多对多正向查询:查询金这本书的所有作者名字
    2     book_obj = Book.objects.filter(title="").first()
    3     author_list = book_obj.authors.all()  # queryset
    4 
    5     for author in author_list:  # 循环queryset拿到每一个object
    6         print(author.name)  # 调用对象下的属性

      (2)多对多反向查询:

    1     # 多对多反向查询:查询alex出版过的所有书籍名称
    2     author_obj = Author.objects.filter(name="alex").first()
    3     book_list = author_obj.book_set.all()
    4 
    5     for book in book_list:
    6         print(book.title)

    一对一:

    1     一对一查询:
    2     正向查询按字段
    3     反向查询按表名
    4     
    5                               (正)author_obj.authordetail
    6         Author(关联属性:authorDetail)  ------------------------>   AuthorDetail
    7                               (反)authordetail_obj.author

    实例:

      (1)一对一正向查询:

    1     # 一对一正向查询:查询alex的手机号
    2     alex = Author.objects.filter(name="alex").first()
    3     print(alex.authordetail.telephone)

      (2)一对一反向查询:

    1     # 一对一反向查询:查询手机号为110的作者名
    2     phone = AuthorDetail.objects.filter(telephone=110).first()
    3     print(phone.author.name)

    2.基于双下划线查询:

      步骤:

        00.记住格式:表名.object.filter(表名小写="").value("")

        01.找到问题的切入点,找到一个表的对象当主对象,例如:Book.object

        02.看主对象是否有能够直接找到的本表数据,如果有,则在filter中获取,如果则在value里查找

        03.用__进行跨表操作

    案例:

     1 #一对多查询:查询金这本书的出版社名字
     2     #方式一
     3     ret = Book.objects.filter(title="").values("publish__name")
     4     print(ret)  # <QuerySet [{'publish__name': '北京出版社'}]>
     5 
     6     #方式二
     7     ret = Publish.objects.filter(book__title="").values("name")
     8     print(ret)
     9 
    10 
    11     #多对多查询:查询金这本书的所有作者名字
    12 
    13     #方式一:
    14     ret = Book.objects.filter(title="").values("authors__name")
    15     print(ret)  # <QuerySet [{'authors__name': 'egon'}]>
    16 
    17 
    18     #方式二:
    19     ret = Author.objects.filter(book__title="").values("name")
    20     print(ret)  # <QuerySet [{'name': 'egon'}]>
    21 
    22 
    23 
    24     #一对一查询:查询alex手机号
    25     ret = Author.objects.filter(name="alex").values("authordetail__telephone")
    26     print(ret)

    3.基于下划线的跨表查询(连续跨表)

    实例:

    1     #手机号以110开头的作者出版过的所有书籍名称以及书籍出版社名称
    2     #方法一
    3     ret = Book.objects.filter(authors__authordetail__telephone__startswith="110").values("title","publish__name")
    4     print(ret)
    5 
    6     #方法二:
    7     ret = Author.objects.filter(authordetail__telephone__startswith="110").values("book__title","book__publish__name")
    8     print(ret)

    4.聚合查询

      (1)聚合(aggregate) 返回值:字典,而不是queryset

          实例:

    1     #查询所有书籍的平均价格
    2     from django.db.models import Avg, Max, Min, Sum, Count
    3     ret = Book.objects.all().aggregate(Avg("price"), Max("price"))  # 可设置字典的key:avg_price=("属性")_
    4     print(ret)  # {'price__avg': 205.555556}

      (2)分组查询(annotate) 返回值:queryset

          实例:

     1     #单表分组查询
     2 
     3     #查询每一个出版社所在成熟的个数
     4     ret = Publish.objects.values("name").annotate(Count("city"))
     5     print(ret)  # 一个queryset的字典:
     6     # <QuerySet [{'name': '人民出版社', 'city__count': 1}, {'name': '北京出版社', 'city__count': 1}, {'name': '上海出版社', 'city__count': 1}]>
     7     '''
     8     单表分组查询的ORM语法:单表模型.objects.values("group by 的字段").annotate(聚合函数("统计字段"))
     9     
    10     补充知识:
    11     ret = Publish.objects.all() =====翻译成sql语句===== select * from publish
    12     只要包含主键的分组,那么这个分组都毫无意义
    13     ret = Publish.objects.values("name") =====翻译成SQL语句===== select name from publish
    14     
    15     
    16     '''
    17 
    18 
    19     #多表分组查询
    20 
    21     #查询每一个出版社出版的书籍几个数
    22     Book.objects.values("publish_id").annotate(c=Count("nid"))
    23 
    24     #案例一:查询每一个出版社的名称以及出版的数几个数
    25     #方式一:
    26     Publish.objects.values("name").annotate(Count("book__title"))
    27     #方式二:用表的主键id进行分组,再在分组后,整个关联的表中再进行values的select操作
    28     Publish.objects.values("nid").annotate(c = Count("book__title")).values("name","c")
    29 
    30     #案例二:查询每一个作者价格最高的书籍
    31     ret = Author.objects.values("pk").annotate(max_price=Max("book_price")).values("name","max_price")  # pk为该表模型的主键
    32 
    33     #案例三:查询每一个书籍的名称以及对应的作者个数
    34 
    35     ret = Book.objects.values("pk").annotate(c = Count("authors__name")).values("title","c")
    36 
    37     #案例四:统计不止一个作者的图书
    38     ret = Book.objects.values("pk").annotate(c=Count("author__name")).filter(c__gt=1).values("title")
    39     print(ret)

    分组查询总结:

    1     跨表的分组查询模型:三套模型效果一样
    2     01.“每一个”字段后表的模型.objects.values("pk").annotate(聚合函数("关联表__统计字段")).values("表模型的所有字段以及统计字段")
    3     02.“每一个”字段后表的模型.objects.all().annotate(聚合函数("关联表__统计字段")).values("表模型的所有字段以及统计字段")
    4     03.“每一个”字段后表的模型.objects.annotate(聚合函数("关联表__统计字段")).values("表模型的所有字段以及统计字段")

    5.F查询与Q查询

      (1)F查询:

        应用场景:之前构造的过滤器filter都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较

        作用:F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值

        前提:from django.db.models import F

        实例:

     1 # 查询评论数大于收藏数的书籍
     2 
     3    from django.db.models import F
     4    Book.objects.filter(commnetNum__lt=F('keepNum'))
     5 
     6 # Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
     7 
     8 # 查询评论数大于收藏数2倍的书籍
     9     Book.objects.filter(commnetNum__lt=F('keepNum')*2)
    10 
    11 # 修改操作也可以使用F函数,比如将每一本书的价格提高30元:
    12     Book.objects.all().update(price=F("price")+30)

      (2)Q查询:

        应用场景:filter() 等方法中的关键字参数查询都是一起进行“AND” 的。

        作用:如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象

        前提:from django.db.models import Q

        实例:

     1 Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
     2 
     3 bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
     4 等同于下面的SQL WHERE 子句:
     5 
     6 WHERE name ="yuan" OR name ="egon"
     7 你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:
     8 
     9 bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")
    10 查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:
    11 
    12 bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),title__icontains="python")

    注意!!!为已经创建的表增加新的字段需要设置default=0,例如:

    1     read_num = models.IntegerField(default=0)
    2     comment_num = models.IntegerField(default=0)
    
    
    
  • 相关阅读:
    HashMap底层实现原理(JDK1.8)源码分析
    JVM总结
    初识Nosql
    线程池总结
    Linux中常用操作命令
    JAVA—集合框架
    TeKtronix TDS210数字示波器使用简介
    硬盘的物理结构
    Unicode 与 UTF
    I2C串行总线
  • 原文地址:https://www.cnblogs.com/QQL-anatkh/p/9449045.html
Copyright © 2020-2023  润新知