Django(十):多表操作


import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled2.settings")
    import django
    django.setup()
    from app01.models import *
    # 一对一新增,先创建没有外键的数据,然后类的字段等于对象(方式一)
    # authordatil=AuthorDetail.objects.create(phone='43333333',email='667788@qq.com')
    # print(authordatil,type(authordatil))
    # author=Author.objects.create(name='小猴',age=12,authordatil=authordatil)
    # print(author)

    # authordetail=AuthorDetail.objects.create(phone='66666',email='66@qq.com')
    #print(authordetail,type(authordetail))
    #结果:(0.000) INSERT INTO `app01_authordetail` (`phone`, `email`) VALUES ('66666', '66@qq.com'); args=['66666', '66@qq.com']
    #      66666 <class 'app01.models.AuthorDetail'>

    # authordetail=AuthorDetail.objects.create(phone='77777',email='77@qq.com')
    # author=Author.objects.create(name='ff',age=20,authordatil=authordetail)
    # print(author,type(author))
    # 结果:(0.000) INSERT INTO `app01_authordetail` (`phone`, `email`) VALUES ('77777', '77@qq.com'); args=['77777', '77@qq.com']
    #       (0.001) INSERT INTO `app01_author` (`name`, `age`, `authordatil_id`) VALUES ('ff', 20, 12); args=['ff', 20, 12]
    #       Author object <class 'app01.models.Author'>


    #————————————————————————————————
    # 直接指名道姓给authordatil_id赋值
    # author=Author.objects.create(name='lqz',age=17,authordatil_id=3)
    # print(author)

    #————————————————————————————————
    # 一对多增加
    # 不建议这么用
    # publish=Publish.objects.create(nid=1,name='南京出版社',addr='南京东路',email='30633@qq.com')
    # publish=Publish.objects.create(name='北京出版社',addr='北京西路',email='30633@qq.com')
    # book=Book.objects.create(name='在人间',price=12.4,pub_date='2018-08-19',publish=publish)
    # print(book)

    # publish=Publish.objects.filter(name='北京出版社').first()
    # book=Book.objects.create(name='百年孤独',price=12.4,pub_date='2018-08-19',publish_id=publish.nid)
    # print(book)

    #————————————————————————————————
    #  多对多
    # book=Book.objects.create(name='白楼',price=166,pub_date='2017-01-19',publish_id=3)
    # print(book.nid)
    # print(book.name)
    # print(book.price)
    # print(book.authors.all(),type(book.authors))

    #————————————————————————————————
    # 多对多,添加关联关系add,传对应表的(作者表的nid)id   book.authors.add(1,2)
    # 没有返回值
    # ret=book.authors.add(4,8) #4,8对应authors中author_id字段的两条纪录,另一个字段book_id对应book表中的新建book的nid字段
    # ret=book.authors.add(*(2,10))   #   *打散
    # add里面可以传对象,也可以传多个,以逗号分割,也可以*(作者对象,作者对象)
    # author=Author.objects.filter(pk=6).first()
    # print(author.name)
    # book.authors.add(author)

    # ————————————————————————————————
    # remove 解除绑定关系,传author_id(既可以传对象,又可以传author_id,既可以传多个,又可以传一个)
    # book=Book.objects.filter(pk=9).first()
    # ret=book.authors.remove(author.id)
    # ret=book.authors.remove(2)
    # author=Author.objects.filter(pk=6).first()
    # ret=book.authors.remove(author)
    # ret=book.authors.remove(2,5)
    # ret=book.authors.remove(*(2,5))
    # print(ret)

    # ————————————————————————————————
    #clear 一次性全部解除绑定关系
    # book = Book.objects.filter(pk=9).first()
    # book.authors.clear()

    # ————————————————————————————————
    # set  用法跟上面的不太一样,参数,必须传可迭代对象,可以传id,也可以传对象
    # book = Book.objects.filter(pk=9).first()
    # author=Author.objects.filter(pk=6).first()
    # book.authors.set([author])    #set括号内传可迭代对象

    # ————————————————————————————————
    # 先执行clear,在执行add
    # book = Book.objects.filter(pk=9).first()
    # ret=book.authors.all()
    # print(ret,type(ret))

    # ————————————————————————————————
    # 基于对象的多表查询(子查询)
    #    一对一(
    # 查询egon的电话号码(正向查询  按字段)
    # egon=Author.objects.filter(name='egon').first()
    # print(egon)
    # authordatil=AuthorDetail.objects.filter(pk=egon.authordatil_id)
    # print(authordatil)
    # print(egon.authordatil)
    # print(egon.authordatil.phone,type(egon.authordatil))

    # 查询电话号码是 1888883 的作者(反向查询 按表名小写)
    # authordatil=AuthorDetail.objects.filter(phone='1888883').first()
    # print(authordatil.author)
#     一对多
#     查询红楼梦是那个出版社出版的
#     正向查询
#     反向查询
    '''
        A表book(关联自动段)   B表 publish
        # 正向查询   A--->B    关联字段在A,A去查询B表,这叫正向查询,按字段来查
        # 反向查询   B--》A    关联字段在A,B去查询A表,这叫反向查询,按表明小写_set
    '''
    # 正向查询
    # book=Book.objects.filter(name='红楼梦1').first()
    # print(book.publish.name)
    # 反向查询
    # 查询北京出版社出版的所有书
    # publish=Publish.objects.filter(name='北京出版社').first()
    # # print(publish.book_set,type(publish.book_set))
    # print(publish.book_set.all())

#     多对多
#     查询红楼梦1这本书的所有作者(正向,按字段)
#     book=Book.objects.all().filter(name='红楼梦1').first()
#     print(book.authors.all())
#     查询lqz出的所有书(反向查询,按表名小写_set)
#     lqz=Author.objects.filter(name='lqz').first()
#     print(lqz.book_set.all())

    # ————————————————————————————————
    '''
        A表book(关联自动段)   B表 publish
        # 正向查询   A--->B    
        # 反向查询   B-->A 
    总结:一对一  正向:按字段  反向:按表名小写
          一对多  正向:按字段  反向:按表名小写_set
          多对多  正向:按字段  反向:按表名小写_set    
    '''
    # 基于双下划线的多表查询(连表查询)
    # 正向查询按字段, 反向查询按表名小写用来告诉ORM引擎join哪张表
    # 一对多查询
    # 查询北京版社出版过的所有书籍价格,名字(反向   按表名)
    # ret=Publish.objects.filter(name='北京出版社').values('book__price','book__name')
    # print(ret)
    # ret=Book.objects.filter(publish__name='北京出版社').values('price','name')
    # print(ret)
    # 多对多
    # 查询lqz出过的所有书籍的名字(多对多)
    # 正向
    # ret=Book.objects.filter(authors__name='lqz').values('name','price','authors__name','authors__authordatil__phone')
    # ret=Book.objects.filter(authors__name='lqz').values('name','price')
    # print(ret)
    # 反向
    # ret=Author.objects.filter(name='lqz').values('book__name')
    # print(ret)
    # 一对一
    # 查询egon的手机号(正向)
    # ret=Author.objects.filter(name='egon').values('authordatil__phone')
    # print(ret)
    # 反向  按表名小写
    # ret=AuthorDetail.objects.filter(author__name='egon').values('phone')
    # print(ret)
    '''
    总结:用__告诉orm,要连接那个表
        一对一: 正向:按字段  反向:按表名小写 
        一对多:  正向:按字段  反向:按表名小写 
        多对多:  正向:按字段  反向:按表名小写 
    '''
    # 手机号以12开头的作者出版过的所有书籍名称以及出版社名称
    # ret=Book.objects.filter(authors__authordatil__phone__startswith='12').values('name','publish__name')
    # print(ret)
    # ret=AuthorDetail.objects.filter(phone__startswith='12').values('author__book__name','author__book__publish__name')
    # print(ret)
    # ret=Author.objects.filter(authordatil__phone__startswith='12').values('book__name','book__publish__name')
    # print(ret)
    # ret=Publish.objects.filter(book__authors__authordatil__phone__startswith='12').values('name','book__name')
    # print(ret)

    # ————————————————————————————————
    # 聚合
    # 计算所有图书的平均价格
    from django.db.models import Avg,Count,Max,Min,Sum  #avg:平均,count:计数,max:最大值,min:最小值,sum:求和
    # ret=Book.objects.all().aggregate(c=Avg('price'))
    # print(ret)
#     计算所有图书总价
#     ret=Book.objects.all().aggregate(s=Sum('price'))
#     print(ret)
#     最大价格:
#     ret=Book.objects.all().aggregate(c=Max('price'))
#     print(ret)
#     所有图书价格的最大值和最小值 返回结果是字典
#     ret=Book.objects.all().aggregate(c_max=Max('price'),c_min=Min('price'))
#     print(ret)

    # ————————————————————————————————
    # F和Q
    #查询评论数大于阅读数的所有书
    from django.db.models import F,Q
    # F  F() 的实例可以在查询中引用字段
    # ret=Book.objects.filter(commit_num__gt=F('reat_num')).values('name')
    # print(ret)
#     把所有书的价格加1
#     ret=Book.objects.all().update(price=F('price')+1)
#     print(ret)
#     Q函数名字叫在人间,或者price是13的数   |:或  &:和 ~:非
#     ret=Book.objects.all().filter(Q(name='在人间')|Q(price='13'))

    # ret=Book.objects.all().filter(~Q(name='在人间')| Q(price='13'))
    # print(ret)

关于Q、F查询:

F查询

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

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

Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

# 查询评论数大于收藏数2倍的书籍
Book.objects.filter(commnetNum__lt=F('keepNum')*2)

 修改操作也可以使用F函数,比如将每一本书的价格提高30元:

Book.objects.all().update(price=F("price")+30) 

Q查询

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

from django.db.models import Q
Q(title__startswith='Py') 

Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

等同于下面的SQL WHERE 子句:

WHERE name ="yuan" OR name ="egon"

你可以组合& (和)和|(或)  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python")
# 查询评论数大于阅读数的书籍
    from django.db.models import F,Q
    # select * from book where commit_num>read_num;
    # 这样肯定是不行的
    # Book.objects.filter(commit_num__gt=read_num)
    ret=Book.objects.filter(commit_num__gt=F('reat_num'))
    print(ret)
    # 把所有书籍的价格加10
    Book.objects.all().update(price=F('price')+10)
    # ----Q函数,描述一个与,或,非的关系
    # 查询名字叫红楼梦或者价格大于100的书
    ret=Book.objects.filter(Q(name='红楼梦')|Q(price__gt=100))
    print(ret)
    # 查询名字叫红楼梦和价格大于100的书
    ret = Book.objects.filter(Q(name='红楼梦') & Q(price__gt=100))
    print(ret)
    # # 等同于
    ret2=Book.objects.filter(name='红楼梦',price__gt=100)
    print(ret2)
    # 也可以Q套Q
    # 查询名字叫红楼梦和价格大于100  或者 nid大于2
    ret=Book.objects.filter((Q(name='红楼梦') & Q(price__gt=100))|Q(nid__gt=2))
    print(ret)
    # ----非
    ret=Book.objects.filter(~Q(name='红楼梦'))
    print(ret)
    # Q和键值对联合使用,但是键值对必须放在Q的后面(描述的是一个且的关系)
    # 查询名字不是红楼梦,并且价格大于100的书
    ret=Book.objects.filter(~Q(name='红楼梦'),price__gt=100)
    print(ret)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值