zoukankan      html  css  js  c++  java
  • Django框架(九)-- 多表操作:一对一、一对多、多对多的增删改,基于对象/双下划线的跨表查询、聚合查询、分组查询、F查询与Q查询

    一、创建多表模型

    一对一:OneToOneField

    一对多:ForeignKey

    多对多:ManyToManyField

    • 创建表时,会自动添加一个nid字段,并且自增,所以id可以不用手动创建

    • OneToOneField和ForeignKey会自动在后面加上" _id "

    • ManyToManyField会自动创建第三张表

    • 创建表的类,OneToOneField、ForeignKey和ManyToManyField中的to后的主表,
      1、如果用双引号包裹,那么创建主表的类在上在下都可以

      2、如果不用双引号包裹,那么创建主表的类就必须在从表的上方

    二、一对多增删改表记录

    class Publish(models.Model):
        # id如果不写,会自动生成,名字叫nid,并且自增
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        addr = models.CharField(max_length=64)
        email = models.EmailField()
    
    
    class Author(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        # 数字类型
        sex = models.IntegerField()
        # to='AuthorDetail'  加引号,这个表能找到就可以,不用引号,类必须在上面定义
        authordetail = models.OneToOneField(to='AuthorDetail', to_field='id')
    
        def __str__(self):
            return self.name
    
    class AuthorDetail(models.Model):
        id = models.AutoField(primary_key=True)
        phone = models.CharField(max_length=32)
        addr = models.CharField(max_length=64)
    
    
    class Book(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish = models.ForeignKey(to=Publish, to_field='id')
    
        authors = models.ManyToManyField(to=Author)
    
        def __str__(self):
            return self.name

    1、一对多添加记录

    (1)通过 _id 来添加记录

    models.Book.objects.create(name='红楼梦',price=20.0,publish_id=1)

    (2)通过对象添加记录

    # pk 表示主键,一旦主键改变,还是会找到对应的主键来获取对象
    publish = models.Publish.objects.filter(pk=1).first()
    models.Book.objects.create(name='红楼梦',price=34.5,publish=publish)

    2、一对多删除记录

    删除记录同单表删除记录一样

    models.Book.objects.filter(name='红楼梦').first().delete()

    3、一对多修改记录

    (1)通过queryset对象的update方法修改

    # 方式一:通过 _id 修改
    models.Book.objects.filter(pk=1).update(name='西游记',publish_id=1)
    
    # 方式二:通过对象修改
    publish = models.Publish.objects.filter(pk=1).first()
    models.Book.objects.filter(pk=1).update(name='西游记',publish=publish)

    (2)通过对象的属性修改,调用对象的save()方法保存

    # 方式一:通过 _id 修改
    book = models.Book.objects.filter(pk=1).first()
    add()    # 可以传对象,可以传id,可以传多个
    
    
    
    
    book.publish_id = 2
    book.save()
    
    # 方式二:通过对象修改
    publish = models.Publish.objects.filter(pk=2).first()
    book.publish = publish
    book.save()

    三、一对一增删改记录

    一对一的增删改记录和一对多的方法相同,参考一对多的增删改记录

    四、多对多增删改记录

    1、多对多增加记录

    add()    # 可以传对象,可以传id,可以传多个

    (1)通过对象添加记录

    # 为红楼梦这本书添加一个作者
    tom = models.Author.objects.filter(name='tom').first()
    book = models.Book.objects.filter(name='红楼梦').first()
    tony = models.Author.objects.filter(name='tony').first()
    jack = models.Author.objects.filter(name='jack').first()
    book.authors.add(tom)
    # 一次添加两个作者,中间用逗号隔开
    book.authors.add(tony,jack)

    (2)通过 id 添加记录

    book = models.Book.objects.filter(name='红楼梦').first()
    book.authors.add(1)
    # 一次添加两个作者,中间用逗号隔开
    book.authors.add(1,2)

    2、多对多删除记录

    remove()    # 可以传对象,可以传id,可以传多个

    (1)通过对象删除记录

    # 删除红楼梦作者名字是tom的作者
    tom = models.Author.objects.filter(name='tom').first()
    book = models.Book.objects.filter(name='红楼梦').first()
    book.authors.remove(tom)

    (2)通过id删除记录

    # 删除红楼梦作者id是1、2的两个作者
    book = models.Book.objects.filter(name='红楼梦').first()
    book.authors.remove(1,2)

    3、多对多清空记录

    clear()    # 没有参数
    # 清除红楼梦的所有作者
    book = models.Book.objects.filter(name='红楼梦').first()
    book.authors.clear()

    4、多对多修改记录

    set()    # 先清空在增加,必须传列表,列表里面可以是对象,可以是id

    (1)通过对象修改记录

    # 修改红楼梦作者名字为tom
    tom = models.Author.objects.filter(name='tom').first()
    book = models.Book.objects.filter(name='红楼梦').first()
    book.authors.set([tom,])

    (2)通过id修改记录

    # 修改红楼梦作者为作者id是1、2的作者
    book = models.Book.objects.filter(name='红楼梦').first()
    book.authors.set([1,2])

    五、基于对象的跨表查询--多次查询、子查询

    正向查询和反向查询

    正向查询:关联字段在从表,由从表查询主表中的数据    -----> 按字段查询
    反向查询:关联字段在从表,由主表查询从表中的数据    -----> 按表名小写查询

    1、一对一基于对象的跨表查询

    正向:正向查询按 字段
    反向:反向查询按 表名小写
    # 1.正向 查询红楼梦这本书的出版社邮箱
    book=Book.objects.filter(name='红楼梦').first()
        # book.publish  就是出版社对象
    pulish=book.publish
    print(pulish.email)
    
    # 2.反向  查询地址是北京的出版社出版的图书
    publish=Publish.objects.filter(addr='北京').first()
        # publish.book_set.all()  拿出所有的图书
    books=publish.book_set.all()
        # 统计一下条数
    books=publish.book_set.all().count()
    print(books)

    3、多对多基于对象的跨表查询

    正向:正向查询按 字段.all()
    反向:反向按 表名小写_set.all()
    # 1.查询红楼梦这本书所有的作者
    book=Book.objects.filter(name='红楼梦').first()
    book.authors.all()  # 是所有的作者,是一个queryset对象,可以继续点
    print(book.authors.all())
    
    # 2.查询lqz写的所有书
    lqz=Author.objects.filter(name='lqz').first()
    books=lqz.book_set.all()
    print(books)

    六、基于双下划线的跨表查询

    1、一对一的基于双下划线的跨表查询

    正向:按 字段,跨表可以在filter,也可以在values中
    反向:按 表名小写,跨表可以在filter,也可以在values中
    # 1.查询tom作者的手机号   正向查询  跨表的话,按字段
       # 以author表作为基表
        ret=Author.objects.filter(name='tom').values('authordetail__phone')
        print(ret)
        
    # 2.以authordetail作为基表 反向查询,按表名小写  跨表的话,用表名小写
        ret=AuthorDetail.objects.filter(author__name='tom').values('phone')
        print(ret)

    3、多对多的基于双下划线的跨表查询

    正向:按 字段,跨表可以在filter,也可以在values中
    反向:按 表名小写,跨表可以在filter,也可以在values中
    # 查询红楼梦的所有作者名字
    # 1.以Book为基表
    ret=Book.objects.filter(name='红楼梦').values('authors__name')
    print(ret)
    
    # 2.以Author为基表
    ret = Author.objects.filter(book__name='红楼梦').values('name')
    print(ret)

    4、连续跨表查询

    一直用双下划线 __ 获取字段

    # 查询红楼梦这本书所有的作者的手机号
    book=Book.objects.filter(name='红楼梦').first()
    authors=book.authors.all()
    for author in authors:
        authordetail=author.authordetail
        print(authordetail.phone)
    
    # 方法二,使用连续跨表
    ret = Book.objects.filter(name='红楼梦').values('authors__authordetails__phone')
    print(ret)

    七、聚合查询

    1、什么聚合

    用聚合函数来汇总多条信息

    2、语法

    from django.db.models import Avg,Sum,Count,Max,Min
    aggregate(*args, **kwargs)

    3、聚合函数使用

    # 聚合函数
    Max('price'),Min('price'),Avg('price'),Sum('price')
    # 计算所有图书的平均价格
    ret = models.Book.objects.all().aggregate(Avg('price'))
    print(ret)
    
    # 计算图书的最高价格,最低价格,平均价格,总价
    ret = models.Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price'))
    print(ret)

    八、分组查询

    1、关键注意点

    values在前,表示group by,在后,表示取值
    filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤)

    2、分组查询案例

    # 查询所有作者写的书的总价格大于26的
    # filter()在annotate后面,表示对分组后的结果进行筛选,相当于having
    # annotate前的values()表示按该字段分组,相当于group by,可以省略,默认会按Author的id分组
    # 后面的values()表示取值
    ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=26).values('name','s')
    
    等价于
    
    ret=Author.objects.all().annotate(s=Sum('book__price')).filter(s__gt=26).values('name','s')
    # 查询各个作者出的书的总价格
    # s相当于给求和结果取名字,在vlaues取值中,可以引用
    ret = Author.objects.all().annotate(s=Sum('price')).values('name','s')
    print(ret)
    # 统计不止一个作者的图书
    ret=Book.objects.all().values('pk').annotate(c=Count('authors')).filter(c__gt=1).values('name','c')
    print(ret)
    
    等价于
    
    ret = Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num')
    print(ret)
    

    九、F查询和Q查询

    1、F查询

    (1)什么是F查询

    如果要对两个字段的值作比较,就不能直接比较,必须要借助F() 的实例,它可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

    (2)语法

    from django.db.models import F
    fliter(commit_num__gt=F('read_num'))
    

    (3)F查询的使用

    # 查询评论数大于阅读数的书
    book = models.Book.objects.filter(commit_num__gt=F('read_num')).values('name')
    
    # 把所有书的评论数加1
    models.Book.objects.all().update(commit_num=F('commit_num')+1)

    2、Q查询

    (1)什么是Q查询

    对两个字段的值进行 且、或、非 运算,不能直接运算,需要用Q()的实例

    (2)语法

    # 且  ----->  &
    # 或  ----->  |
    # 非  ----->  ~
    from django.db.models import Q
    fliter(Q(name='tom')|Q(name='tony'))

    (3)Q查询的使用

    # 查询不是tom写的书的名字
    ret = models.Book.objects.filter(~Q(authors__name='tom')).values('name')
    
    # 查询作者名字是tom或者名字是tony的书
    ret = models.Book.objects.filter(Q(authors__name='tom')|Q(authors__name='tony')).values('name')

      

  • 相关阅读:
    数据库学习 ORA12545:因目标主机或对象不存在,连接失败
    Oracle创建命名空间和新用户
    创建一个命名空间
    修改用户密码
    Oracle启动
    数据库表中列类型的修改和ALTER的用法
    修改列类型
    IE6/IE7/IE8/Firefox/Chrome/Safari的CSS hack兼容一览表
    css:fixed定位兼容不同系列不同版本的浏览器包括IE6.0
    jQuery Google Charts一个封装google chart api的jquery插件 饼状图
  • 原文地址:https://www.cnblogs.com/zhangbingsheng/p/10634239.html
Copyright © 2011-2022 走看看