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)