• Django中模型层中ORM的多表操作


    ORM的多表创建(一对一.一对多,多对多):

    1模型创建

      实例:我们来假定下面这些概念,字段和关系

    作者模型:一个作者有姓名和年龄。

    作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

    出版商模型:出版商有名称,所在城市以及email。

    书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

    模型建立如下:

    from django.db import models
    
    
    # Create your models here.
    
    class Book(models.Model):
        id = models.AutoField(primary_key=True)  # 可不填,Django会自动帮你写
        title = models.CharField(max_length=32)
        pub_date = models.DateField()
        price = models.DecimalField(max_digits=5, decimal_places=2)
        # 与Publish(id)建立一对多的外键关系
        publish = models.ForeignKey(to="Publish", to_field="id", on_delete=models.CASCADE)
        # 创建多对多的关系,不会添加外键,会另外创建表格
        authors = models.ManyToManyField(to="Author")
    
        def __str__(self):
            return self.title
    
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        # 与authorDetail建立一对一的外键关系
        authorDetail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)
    
        def __str__(self):
            return self.name
    
    
    class AuthorDetail(models.Model):
        birthday = models.DateField()
        phone = models.BigIntegerField()
        addr = models.CharField(max_length=64)
    
        def __str__(self):
            return self.addr
    
    
    class Emp(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        salary = models.DecimalField(max_digits=8, decimal_places=2)
        dep = models.CharField(max_length=32)
        province = models.CharField(max_length=32)
    
        def __str__(self):
            return self.name
    
    
    class Article(models.Model):
        title = models.CharField(max_length=32)
        comment_num = models.IntegerField()
        poll_num = models.IntegerField()
    
        def __str__(self): return self.title
    View Code

    注意事项:

    •  表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  
    •  id 字段是自动添加的
    •  对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
    •  这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
    •  定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
    • 外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

    2.多表记录的操作

    2.1 多表操作之表记录的创建

      2.1.1一对一以及一对多记录的创建:

    1  方式一
    2     book = models.Book.objects.create(title="java",price=122,pub_date="2012-02-12",publish_id=1)
    3 
    4     方式二
    5     pub_obj = models.Publish.objects.filter(name="西瓜出版社").first()
    6     book = models.Book.objects.create(title="PHP", price=122, pub_date="2014-02-12", publish = pub_obj)
    7     print(book.title)
    8     print(book.publish_id)
    View Code

      2.1.2 多对多记录的创建

     ######################### 绑定多对多的关系;无非是在关系表创建记录 ##########################
        tips: 正向操作按字段,反向操作按表名小写(一定要记住)
    
        为java这本书绑定两个作者: 大锤,尼玛(正向绑定):
        添加方式一
        java = models.Book.objects.filter(title="java").first()
        dachui = models.Author.objects.filter(name="王大锤").first()
        nima =  models.Author.objects.filter(name="王尼玛").first()
        print(java.price)
        print(dachui.name)
        print(nima.name)
        java.authors.add(dachui,nima)
    
        添加方式二
        java.authors.add(2)
        java.authors.add(*[3,2])   #添加的另外一种方式,较常用,[]内为对应作者的ID,*用于打散
    
        移除两个作者与java的绑定关系
        java.authors.remove(dachui, nima) # 将某个特定的对象从被关联对象集合中去除。== book_obj.authors.remove(*[])
    
        java.authors.clear() #清空被关联对象集合
    
        重新赋值关系
        java.authors.set([3,])  #重新设置值,先clear,在赋值
    
    
        给王大锤作者绑定两本书籍: PHP,Go(反向绑定)
        dachui = models.Author.objects.filter(name="王大锤").first()
        PHP = models.Book.objects.filter(title="PHP").first()
        Go = models.Book.objects.filter(title="Go").first()
        方式一:
        dachui.book_set.add(PHP, Go)   ###此处因为是反向绑定采用的是 表名_set
        方式二
        dachui.book_set.add(*[3,4])
    View Code

    2.2多表操作之跨表查询

    2.2.1基于对象的跨表查询

      总的查询思路

      一 基于对象的跨表查询( 子查询:以上一次的查询结果作为下一次的查询条件)
           (1)一对多
                             正向查询:按字段 book.publish
             Book对象    ---------------------------------- >  Publish 对象
                          <---------------------------------
                            反向查询:按表名小写_set.all()
    
    
            (2)多对多
                           正向查询:按字段 book.authors.all()
             Book对象    ---------------------------------- >  Author 对象
                          <---------------------------------
                            反向查询:按表名小写_set.all()
    
    
            (2)一对一
                            正向查询:按字段 book.ad
             Author 对象   ---------------------------------- >  AuthorDetail 对象
                          <---------------------------------
                            反向查询:按表名小写

      2.2.1.1 基于对象的一对多的跨表查询

    (1)一对多
    
        1 查询PHP这本书籍的出版社的地址(正向查询)
        addr = models.Book.objects.filter(title="PHP").first().publish.city
        print(addr)
    
    
        2 查询香蕉出版社出版的所有书籍(反向查询)
        queryset = models.Publish.objects.filter(name="西瓜出版社").first().book_set.all()
        print(queryset)
    View Code

      2.2.1.2 基于对象的多对多的跨表查询

     (2)多对多
    
        1 查询java书籍的所有作者
        queryset = models.Book.objects.filter(title="java").first().authors.all()
        print(queryset)
    
        2 查询王大锤作者出版过得所有书籍
        queryset = models.Author.objects.filter(name="王大锤").first().book_set.all()
        print(queryset)
    View Code

      2.2.1.3 基于对象的一对一的跨表查询

    (3)一对一
        1  查询王大锤的手机号
        phone = models.Author.objects.filter(name="王大锤").first().authorDetail.phone
        print(phone)
    
        2 查询手机号为123的作者的名字
        name = models.AuthorDetail.objects.filter(phone="123").first().author.name
        print(name)
    View Code

    2.2.2  基于双下划綫的跨表查询:

     KEY: 通知ORM引擎如何跨表: 正向查询按字段, 反向查询按表名小写

    2.2.2.1基于双下划线的跨表查询(join查询)

     ################基于双下划线的跨表查询(join查询)##########################
        1 查询PHP这本书籍的出版社的地址
        '''
         SELECT app01_publish.city from app01_book INNER JOIN app01_publish 
                                      ON app01_book.publish_id = app01_publish.id 
                                      WHERE app01_book.title ="PHP"
        '''
    方式1
        queryset_addr = models.Book.objects.filter(title="PHP").values("publish__city")
        print(queryset_addr)
    
        方式2
        queryset_addr = models.Publish.objects.filter(book__title="PHP").values("city")
        print(queryset_addr)
    
    
        2 查询java书籍的所有作者
        queryset_author = models.Book.objects.filter(title="java").values("authors__name")
        queryset_author = models.Book.objects.filter(title__startswith="P").values("authors__name")
        print(queryset_author)
    
        3  查询唐马儒的手机号
        queryset_tel = models.Author.objects.filter(name="唐马儒").values("authorDetail__phone")
        queryset_tel = models.AuthorDetail.objects.filter(author__name="唐马儒").values("phone")
        print(queryset_tel)
    View Code

    2.2.2.2 连续跨表操作及其示例:

    连续跨表
        4 查询西瓜出版社出版过的所有书籍的名字以及作者的姓名
        queryset_info = models.Book.objects.filter(publish__name="西瓜出版社").values("title","authors__name")
        queryset_info = models.Author.objects.filter(book__publish__name="西瓜出版社").values("book__title","name")
        print(queryset_info)
    
        5 手机号以151开头的作者出版过的所有书籍名称以及出版社名称
        queryset_info = models.Book.objects.filter(authors__authorDetail__phone__startswith="1").values("title","publish__name")
        print(queryset_info
    View Code

    2.2.3  聚合查询:

    1 ######################聚合查询#############################3
    2     aggregate()
    3 
    4     from django.db.models import Avg,Max,Min,Count
    5     1.计算所有人的平均工资
    6     ret = models.Emp.objects.all().aggregate(平均工资=Avg("salary"))
    7     print(re

    2.2.4  单表分组查询:

        ############## 单表分组查询  ###############
    查询每一个部门的人数
        ret = models.Emp.objects.values("dep").annotate(Count("id"))
    
    查询省份名字有东的部门的人数
        ret = models.Emp.objects.filter(province__contains="").values("dep").annotate(c = Count("id"))
        print(ret)
    
    # 查询每一个省份的平均薪水
        ret = models.Emp.objects.values("province").annotate(avg_salary=Avg("salary"))
        print(ret)

    2.2.4  多表分组查询:

    ############## 多表分组查询  ###############
    
        1 查询每一个出版社的名字和出版过的书籍的平均价格
        querryset = models.Publish.objects.values("name").annotate(avg_salary=Avg("book__price"))
        querryset = models.Publish.objects.annotate(avg_salary=Avg("book__price")).values("name","avg_salary")
        print(querryset)
    
        2 查询每一个作者的名字以及出版书籍的个数
        querryset = models.Author.objects.values("name").annotate(c = Count("book__id"))
        querryset = models.Author.objects.annotate(c = Count("book__id")).values("name","c")
        print(querryset)
    
        3 查询每一个书籍的名称以及作者的个数
        querryset = models.Book.objects.values("title").annotate(c = Count("authors__id"))
        print(querryset)
    
    
        4 查询作者个数大于1 的每一本书籍的名称和作者个数
    
        querryset = models.Book.objects.annotate(c = Count("authors__id")).filter(c__gt=1).values("title","c")
        print(querryset)
    
        5 查询书籍名称包含"h"的书籍名称和作者个数
        querryset = models.Book.objects.filter(title__contains="P").annotate(c = Count("authors__id")).values("title","c")
        querryset = models.Book.objects.annotate(c=Count("authors__id")).filter(title__contains="P").values("title", "c")
        print(querryset)

    2.2.4  F与Q查询:

    F查询: 在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

    Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

    Q查询:filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q对象

    ##################################### F查询与Q查询
    
         F查询
        from django.db.models import F,Q,Avg
        1 查询评论数大于100的文章
        ret = models.Article.objects.filter(comment_num__gt=300)
        print(ret)
    
        2 查询评论数大于点赞数的文章
        ret = models.Article.objects.filter(comment_num__gt=F("poll_num"))
        print(ret)
    
    
        3 查询评论数大于两倍点赞数
        ret = models.Article.objects.filter(comment_num__gt = F("poll_num")*2)
        print(ret)
    
        4 将所有的书籍的价格提高100元
        ret = models.Book.objects.update(price = F("price")+10)
        print(ret)
    
    
        Q查询
        5 查询价格大于300或者名称以p开头的书籍
        Q : & | ~
        ret = models.Book.objects.filter(Q(price__gt=150)|Q(title__startswith="P"))
        print(ret)
    
        # 5 查询价格大于300或者不是2012年2月份的书籍
        ret = models.Book.objects.filter(Q(price__gt=140) | Q(Q(pub_date__year=2012)&Q(pub_date__month=2)))
        ret = models.Book.objects.filter(Q(price__gt=140) | Q(pub_date__year=2012) & Q(pub_date__month=2))
        ret = models.Book.objects.filter(Q(price__gt=140) | Q(pub_date__year=2012,pub_date__month=2))
        print(ret)
    View Code

    详细请参考:ORM多表查询

     

  • 相关阅读:
    I2C驱动程序
    3.4.2内核下的I2C驱动
    ARM Linux bootloader笔记
    将博客搬至CSDN
    《淘宝技术这十年》读后感
    《华为研发》2读后感
    《大数据》涂子沛【3.0升级版】读后感
    Cadence画封装的步骤
    Cadence PCB层的概念
    fPLL结构及动态配置
  • 原文地址:https://www.cnblogs.com/Mixtea/p/10469839.html
Copyright © 2020-2023  润新知