• Django之模型层-多表操作


    多表操作

    数据库表关系

    1. 一对多:两个表之间的关系一旦确定为一对多,必须在数据多的表中创建关联字段
    2. 多对多:两个表之间的关系一定确定为多对多,必须创建第三张表(关联表)
    3. 一对一:一旦两个表之间的关系确定为一对一,在两种表中任意一张表中建立关联字段unique

    ORM生成关联表模型

    class Book(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=8,decimal_places=2)
        # 出版社信息
        # 一对多
        publish = models.ForeignKey(to='Publish',to_field='id',on_delete=models.CASCADE)
    
        # 多对多
        author = models.ManyToManyField(to='Author')
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        email = models.EmailField()
    
    class Author(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
        # 一对一
        authorDetails = models.OneToOneField(to='AuthorDetails',to_field='id',on_delete=models.CASCADE)
        def __str__(self):
            return self.name
    
    class AuthorDetails(models.Model):
        id = models.AutoField(primary_key=True)
        city = models.CharField(max_length=32)
        phone = models.IntegerField()
    
    
    
    • 创建表关系方法:
      • 一对一:OneToOneField()
      • 一对多:ForeignKey()
      • 多对多:ManyToManyField()
    • 表关系模型创建注意事项
      • 创建关联表时不需要在关联字段后面加_id,ORM会自动加

      • 关联表关系:一对多关系
        to=表的时候可以加引号也可以不加,不加引号的话必须被关联的表在关联表上面,to_field也可以不写主键,不写的话默认是关联表的主键

      • on_delete=models.CASCADE在一对多的时候必须要加,一对多的时候也必须要加,如果不加会报on_delete错误

      • null = True 允许关联字段为空

      • 在生成表关系多对多的时候,会另外生成第三张表,不会在该表内生成

    多表操作之添加记录

    添加记录时先添加单表的记录(不关联其他表的表),插入时与单表插入一样。然后插入与其他表关联了的表的记录,有两种插入方式:

    方式1:直接传入一个关联的键

    Books.objects.create(b_name='红楼梦',price=100,author_id=1,publish_id=2)
    

    方式2:传入一个模型对象

    publish_obj = Publish.objects.filter(id='1')[0]
    Books.objects.create(b_name='红楼梦',price=100,author_id=1,publish=publish_obj)
    

    在使用关联字段的时候,可以使用字段名_id,也可以直接使用字段名,使用字段名是打印的一个模型对象,使用字段名_id的话打印的是一个关联的键

    book_obj = Books.objects.filter(bid=1)[0]
    print(book_obj.b_name)
    print(book_obj.publish) #Publish object (2)
    print(book_obj.publish.p_name) #南京出版社
    print(book_obj.publish_id) # 2
    

    绑定多对多关系

    book = Publish.objects.filter(id__gt=2).delete()
    cao = Author.objects.get(name='曹雪芹')
    luo = Author.objects.get(name='罗贯中')
    book.author.add(cao,luo)
    

    解除多对多的关系,先找到需要解除的对象

    # 参数可以是一个主键也可以是模型对象
    book.author.remove(1)
    

    清空多对多关系

    book.author.clear()
    

    获取一个模型所有的关联对象

    print(book.author.all())
    

    设置多对多关系

    # set函数相当于是先清空了(clear)数据,然后再重新赋值,赋值参数是一个可迭代对象
    book.author.set(列表)
    

    跨表查询

    正向查询:假设关联属性在A表中,通过A查询B对象就是属于正向查询,正向查询按字段

    反向查询:假设关联属性在A表中,通过B查询A对象就是属于正向查询,反向查询按表名小写_set

    基于对象查询(子查询)

    • 一对多的查询
    # 一对多的正向查询:查询红楼梦这本书的出版社名字
    book = Book.objects.filter(title='红楼梦')[0]
    print(book.publish.name)
    
    # 一对多的反向查询:查某个出版社出版过的书籍
    publish_obj = Publish.objects.get(name='南京出版社')
    ret = publish_obj.book_set.all()
    print(ret)
    
    • 多对多的查询
    # 多对多的正向查询:查询红楼梦这本书所有作者的名字
    book = Book.objects.filter(title='红楼梦')[0]
    ret = book.author.all()
    print(ret)
    # 多对多的反向查询:查询曹雪芹写过的书
    author = Author.objects.filter(name='曹雪芹')[0]
    ret = author.book_set.all()
    print(ret)
    
    • 一对一的查询
        # 一对一的正向查询:查询名字为曹雪芹的所在城市
        auth = Author.objects.filter(name='曹雪芹').first()
        print(auth.authorDetails.city)
    
        # 一对一的反向查询:查询在江苏的作者的名字
        ad = AuthorDetails.objects.filter(city='江苏').first()
        print(ad.author.name)
    
    

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

    正向查询按字段,反向查询按表名小写

    双下划线就相当于需要关联哪一张表,相当于sql语句中的join

    一对多

    # 一对多的正向查询查询红楼梦的出版社名字
    # 方式1
    ret = Book.objects.filter(title='红楼梦').values('publish__name')
    print(ret)
    # 方式2
    ret = Publish.objects.filter(book__title='红楼梦').values('name')
    

    多对多

     # 查询红楼梦的作者的名字
     # 方式1
    ret = Book.objects.filter(title='红楼梦').values('author__name')
    print(ret)
     # 方式2
     ret = Author.objects.filter(book__title='红楼梦').values('name')
    

    一对一查询

    # 查询曹雪芹所在的城市
    # 正向查询
    ret = Author.objects.filter(name='曹雪芹').values('authorDetails__city')
    # 反向查询
    ret = AuthorDetails.objects.filter(author__name='曹雪芹').values('city')
    # print(ret)
    

    连续跨表查询

    # 手机号以15开头的作者出版过的书籍以及出版社的名称
    # 正向查询
    ret = Book.objects.filter(author__authorDetails__phone__startswith=151).values('title','publish__name')
    # 反向查询
    ret = Author.objects.filter(authorDetails__phone__startswith='151').values('book__title','book__publish__name')
    print(ret)
    

    聚合查询

    aggregate()函数

    # 查询所有书籍的平均价格
    # 聚合查询:聚合函数aggregate
    from django.db.models import Avg,Max,Min,Count,Sum
    ret = Book.objects.all().aggregate(Avg('price')) #返回值是一个字典
    print(ret)
    

    分组查询

    annotate()

    单表分组

    单表分组查询的ORM语法:单表模型.objects.values('group by字段').annotate(聚合函数("统计字段")

    from django.db.models import Avg,Max,Min,Count,Sum
    ret = Emp.objects.values('dep').annotate(avg_salary=Avg('salary'))
    print(ret)
    

    多表分组查询

    多表查询分组语句模型:

    每一个后表模型.objects.value('主键').anntota(聚合函数(关联表__ 字段)).values('表模型字段以及所有统计字段')

     # 查询出版社名称以及出版社出版的书籍数量
    # 方式1
    ret = Publish.objects.values('name').annotate(count=Count('book__title'))
    print(ret)
    # 方式2
    ret = Publish.objects.values('id').annotate(count=Count('book__title')).values('name','count')
    print(ret)
    
    # 查询每一个作者出版过的书籍的最高价格
    ret = Author.objects.values('id').annotate(max_price = Max('book__price')).values('name','max_price')
    print(ret)
    

    F 与 Q查询

    • F查询

    用于在一张表内两个字段进行比较查询,F对象内放的是同一张表的字段,对表进行批量操作也可以使用该类

    from django.db.models import F
    # 查询评论数大于阅读数
    ret = Book.objects.filter(comment_num__gt=F("reda_num"))
    
    # 所有书籍的价格加10
    Book.objects.all().update(price=F('price')+10)
    
    
    • Q查询

    filter()等方法中的关键字参数查询都是一起进行‘AND'的,如果需要执行更复杂的查询,可以使用Q对象

    Q对象可以使用&、|、~操作符组合起来使用并且可以使用括号进行分组编写任意复杂的Q对象

    查询名字是红楼梦的书籍或者价格大于20元的书籍
    from django.db.models import F,Q
    ret = Book.objects.filter(read_num__gt=F('comment_num'))
    print(ret)
    ret = Book.objects.filter(Q(title='红楼梦')|Q(price__gt=20))
    print(ret)
    
  • 相关阅读:
    第八篇 EBS实现企业日常业务运管模型的解决方案设计思路
    第7篇 ORACLE EBS DEMO虚拟机环境的安装
    第六篇 ORACLE EBS用户界面通用元素或功能背后的道理解析
    第五篇 Getting Started with ORACLE EBS(开始学习ORACLE EBS)
    嵌入式根文件系统的移植和制作详解
    性能测试工具
    UEFI GPT
    系统启动过程和系统安装过程
    Gentoo安装
    Gentoo源码安装图解
  • 原文地址:https://www.cnblogs.com/wualin/p/10115983.html
Copyright © 2020-2023  润新知