多表关联创建增删改查,一对一,一对多,多对多
创建表
from django.db import models # Create your models here. #作者表 class Author(models.Model): #比较常用的信息放到这个表里面 name=models.CharField( max_length=32) age=models.IntegerField() # 与AuthorDetail建立一对一的关系,一对一的这个关系字段写在两个表的任意一个表里面都可以 authorDetail=models.OneToOneField(to="AuthorDetail",to_field="id",on_delete=models.CASCADE) #就是foreignkey+unique,只不过不需要我们自己来写参数了,并且orm会自动帮你给这个字段名字拼上一个_id,数据库中字段名称为authorDetail_id def __str__(self): return self.name #作者详细信息表 class AuthorDetail(models.Model):#不常用的放到这个表里面 birthday=models.DateField() telephone=models.CharField(max_length=32) addr=models.CharField( max_length=64) def __str__(self): return self.telephone #出版社表 和 书籍表 一对多的关系 class Publish(models.Model): name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() #charField类似,EmailField做邮箱数据校验使用 def __str__(self): return self.name #多对多的表关系,我们学mysql的时候是怎么建立的,是不是手动创建一个第三张表,然后写上两个字段,每个字段外键关联到另外两张多对多关系的表,orm的manytomany自动帮我们创建第三张表,两种方式建立关系都可以,以后的学习我们暂时用orm自动创建的第三张表,因为手动创建的第三张表我们进行orm操作的时候,很多关于多对多关系的表之间的orm语句方法无法使用 #如果你想删除某张表,你只需要将这个表注销掉,然后执行那两个数据库同步指令就可以了,自动就删除了。 #书籍表 class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2)#Decimal ,max_digits整数加小数位数,decimal_places小数位数 # 与Publish建立一对多的关系,外键字段建立在多的一方,字段publish如果是外键字段,那么它自动是int类型 publishs=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE) #foreignkey里面可以加很多的参数,都是需要咱们学习的,慢慢来,to指向表,to_field指向你关联的字段,不写这个,默认会自动关联主键字段,on_delete级联删除字段名称不需要写成publish_id,orm在翻译foreignkey的时候会自动给你这个字段拼上一个_id,这个字段名称在数据库里面就自动变成了publish_id # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表,并且注意一点,你查看book表的时候,你看不到这个字段,因为这个字段就是创建第三张表的意思,不是创建字段的意思,所以只能说这个book类里面有authors这个字段属性 authors=models.ManyToManyField(to='Author',) #注意不管是一对多还是多对多,写to这个参数的时候,最后后面的值是个字符串,不然你就需要将你要关联的那个表放到这个表的上面 def __str__(self): return self.title
增删改操作:
#增删改查 #1增 #1.1一对一增加 ''' #作者信息表 author_detail = models.AuthorDetail.objects.create( birthday='2000-01-13', telephone='15265891211', addr='上海浦东新区', ) #作者表 # 方式1:直接使用authorDetail使用对象来创建 models.Author.objects.create( name='李白', age='56', authorDetail=author_detail, ) # 方式2:使用数据库字段名称来创建 models.Author.objects.create( name='苏轼', age='47', authorDetail_id=author_detail.id, ) ''' ''' #1.2一对多 #方式1:使用对象 models.Book.objects.create( title = '钢铁怎样炼成', publishDate='2019-03-26', price = 17.8, publishs=models.Publish.objects.filter(id=2).first(), # publishs=models.Publish.objects.get(id=2), ) #方式2:使用属性字段 models.Book.objects.create( title = '木棒怎样炼成', publishDate='2017-03-26', price = 27.8, publishs_id=models.Publish.objects.get(id=2).id ) ''' #多对多 #方式1:创建一个找到一个book对象,就可以调book表中的authors属性来添加对应的作者id,注意这儿使用add方法 ''' book_obj = models.Book.objects.get(nid=8) book_obj.authors.add(*[1,4]) ''' #方式2:使用对象 (不推荐使用) ''' AUTHOR1=models.Author.objects.get(id=3) AUTHOR2 = models.Author.objects.get(id=4) AUTHOR3 = models.Author.objects.get(id=1) book_obj1 = models.Book.objects.get(nid=7) book_obj1.authors.add(*[AUTHOR1,AUTHOR2,AUTHOR3]) ''' #删除 一对一,多对多的删除和单表删除是一样的 ''' # 一对一 、一对多。删除被依赖的依赖的也被删除。删除依赖被依赖的不会删除 models.AuthorDetail.objects.get(id=2).delete() #多对多删除 #找到nid为6的书籍, book_obj = models.Book.objects.get(nid=6) #删除作者id为6的数据 book_obj.authors.remove(6) #删除多个 book_obj.authors.remove(*[6,5]) #删除作者id为6的所有数据 book_obj.authors.clear() #删除所有作者id为6的数据,并添加绑定一条id为1的数据 book_obj.authors.set("1") #绑定一条id为1和5的两条数据,注意这儿不用打散 book_obj.authors.set(["1","5"]) ''' #更新 找到bookid为5,更新绑定信息 ''' #一对一 models.Author.objects.filter(id=5).update( name = '礼拜', age=17, # 根据对象 # authorDetail = models.AuthorDetail.objects.get(id=5), # 根据id更新 authorDetail_id = 4, ) #一对多 models.Book.objects.filter(nid=4).update( title = '钢铁怎么练成', # publishs = models.Publish.objects.get(id=3) publishs_id = 3, ) '''
基于对象的跨表查询 --- 类似于子查询
正向or反向查询:关系属性(字段)写在那个类(表)里面,从当前类的数据去查询它关联类(表)的数据,反之交反向查询。
#查询 """ #一对一 #正向查询 靠关联的属性字段查询 #查询罗贯中地址是什么 author_obj = models.Author.objects.filter(name="罗贯中").first() # author_obj.authorDetail 拿到一对一关联的对象,我们就可以通过属性来获取值 print(author_obj.authorDetail.addr) #北京 #反向查询 根据小写的类名查询 # 查询一下15235412112电话是什么人 author_detail_obj = models.AuthorDetail.objects.get(telephone="15235412112") # author_detail_obj.author 拿到一对一的关联对象,可以通过属性来获取 print(author_detail_obj.author.name) #李白 ''' 正向查询: Authorobj.authorDetail,对象.关联属性名称 Author------------------------------------>AuthorDetail <------------------------------------ 反向查询:AuthorDetailobj.author,对象.类名小写.属性名 ''' """ #一对多 """ # 查询西游记出版社是什么 #正向查询 #查询书名为西游记的对象,调用关联对象,在获取属性 book_obj = models.Book.objects.get(title="西游记") print(book_obj.publishs.name) # 反向查询 #查询新华出版社出版了那些书 publish_obj = models.Publish.objects.get(name='新华出版社') print(publish_obj.book_set.all()) #<QuerySet [<Book: 水浒传>]> ''' 正向查询 book_obj.publishs.属性 Book-------------------------------------------------->Publish <-------------------------------------------------- 反向查询 publish_obj.book_set.all() 对象.表名小写_set ''' """ #多对多 """ #西游记是谁写的 #正向查询 book_obj = models.Book.objects.get(title='西游记') print(book_obj.authors.all()) #<QuerySet [<Author: 罗贯中>, <Author: 吴承恩>]> #查询吴承恩写了那些书 author_obj = models.Author.objects.get(name='吴承恩') print(author_obj.book_set.all()) #<QuerySet [<Book: 西游记>, <Book: 水浒传>, <Book: 钢铁怎样炼成>]> ''' 正向查询 book_obj.表明小写.all() Book-------------------------------------->Author <-------------------------------------- 反向查询 author_obj.表名小写_set.all() ''' """
基于双下划线的跨表查询 --- 连标 join
# 基于双下划线的跨表查询 -- 连标join #一对一 ''' #1.查询罗贯中地址是什么 #方式1 正向查询 addr1 = models.Author.objects.filter(name='罗贯中').values() print(addr1) #<QuerySet [{'id': 1, 'name': '罗贯中', 'age': 36, 'authorDetail_id': 1}]> addr = models.Author.objects.filter(name='罗贯中').values("authorDetail__addr",'name').first() #{'authorDetail__addr': '北京', 'name': '罗贯中'} print(addr) #<QuerySet [{'authorDetail__addr': '北京', 'name': '罗贯中'}]> #方式2 反向查询 obj = models.AuthorDetail.objects.filter(author__name='罗贯中').values('addr','author__age') #<QuerySet [{'addr': '北京', 'author__age': 36}]> print(obj) #电话号码13854712314是谁 #方式1 正向查询 name_obj1 = models.AuthorDetail.objects.filter(telephone='13854712314').values('author__name') #<QuerySet [{'author__name': '吴承恩'}]> print(name_obj1) #方式2 反向查询 name_obj2 = models.Author.objects.filter(authorDetail__telephone='13854712314').values('name') #<QuerySet [{'name': '吴承恩'}]> print(name_obj2) ''' #一对多 ''' # 查询西游记出版社是什么 # 方式1 正向查询 obj = models.Book.objects.filter(title='西游记').values('publishs__name') #<QuerySet [{'publishs__name': 'Cc出版社'}]> print(obj) # 方式2 反向查询 obj1 = models.Publish.objects.filter(book__title='西游记').values('name') #<QuerySet [{'publishs__name': 'Cc出版社'}]> print(obj) #西安出版社出版了那些书 obj2 = models.Publish.objects.filter(name='西安出版社').values('book__title') #<QuerySet [{'book__title': '三国演义'}, {'book__title': '钢铁怎样炼成'}, {'book__title': '木棒怎样炼成'}]> print(obj2) obj3 = models.Book.objects.filter(publishs__name='西安出版社').values('title') #<QuerySet [{'title': '三国演义'}, {'title': '钢铁怎样炼成'}, {'title': '木棒怎样炼成'}]> print(obj3) #钢铁怎样炼成是谁写的 obj4 = models.Book.objects.filter(title='钢铁怎样炼成').values('authors__name') #<QuerySet [{'authors__name': '罗贯中'}, {'authors__name': '吴承恩'}, {'authors__name': '李白'}]> print(obj4) obj5 = models.Author.objects.filter(book__title='钢铁怎样炼成').values('name') #<QuerySet [{'name': '罗贯中'}, {'name': '吴承恩'}, {'name': '李白'}]> print(obj5) #李白写了那些书 obj6 = models.Author.objects.filter(name='李白').values('book__title') #<QuerySet [{'book__title': '红楼梦'}, {'book__title': '钢铁怎样炼成'}, {'book__title': '木棒怎样炼成'}]> print(obj6) obj7 = models.Book.objects.filter(authors__name='李白').values('title') #<QuerySet [{'title': '红楼梦'}, {'title': '钢铁怎样炼成'}, {'title': '木棒怎样炼成'}]> print(obj7) ''' #进阶 三表关联 #查询西安出版社出版的书的名称以及作者名称 #正向查询 obj8 = models.Publish.objects.filter(name='西安出版社').values('book__authors__name','book__title') print(obj8) #<QuerySet [{'book__authors__name': '罗贯中', 'book__title': '三国演义'}, {'book__authors__name': '罗贯中', 'book__title': '钢铁怎样炼成'}, {'book__authors__name': '罗贯中', 'book__title': '木棒怎样炼成'}, {'book__authors__name': '吴承恩', 'book__title': '钢铁怎样炼成'}, {'book__authors__name': '李白', 'book__title': '钢铁怎样炼成'}, {'book__authors__name': '李白', 'book__title': '木棒怎样炼成'}, {'book__authors__name': '苏轼', 'book__title': '三国演义'}]> #反向查询 obj9 = models.Book.objects.filter(publishs__name='西安出版社').values('title','authors__name') print(obj9) #<QuerySet [{'title': '三国演义', 'authors__name': '罗贯中'}, {'title': '钢铁怎样炼成', 'authors__name': '罗贯中'}, {'title': '木棒怎样炼成', 'authors__name': '罗贯中'}, {'title': '钢铁怎样炼成', 'authors__name': '吴承恩'}, {'title': '钢铁怎样炼成', 'authors__name': '李白'}, {'title': '木棒怎样炼成', 'authors__name': '李白'}, {'title': '三国演义', 'authors__name': '苏轼'}]> obj10 = models.Author.objects.filter(book__publishs__name='西安出版社').values('name','book__title') print(obj10) #<QuerySet [{'name': '罗贯中', 'book__title': '三国演义'}, {'name': '罗贯中', 'book__title': '钢铁怎样炼成'}, {'name': '罗贯中', 'book__title': '木棒怎样炼成'}, {'name': '吴承恩', 'book__title': '钢铁怎样炼成'}, {'name': '李白', 'book__title': '钢铁怎样炼成'}, {'name': '李白', 'book__title': '木棒怎样炼成'}, {'name': '苏轼', 'book__title': '三国演义'}]> #进阶2: #手机号以4结尾的作者,出版社过的所有书籍名称以及出版社名称 obj11 = models.AuthorDetail.objects.filter(telephone__endswith='4').values('author__book__title','author__book__publishs__name') print(obj11) #<QuerySet [{'author__book__title': '水浒传', 'author__book__publishs__name': '新华出版社'}, {'author__book__title': '钢铁怎样炼成', 'author__book__publishs__name': '西安出版社'}, {'author__book__title': '西游记', 'author__book__publishs__name': 'Cc出版社'}]> obj12 = models.Book.objects.filter(authors__authorDetail__telephone__endswith='4').values('title','publishs__name') print(obj12) #<QuerySet [{'title': '西游记', 'publishs__name': 'Cc出版社'}, {'title': '水浒传', 'publishs__name': '新华出版社'}, {'title': '钢铁怎样炼成', 'publishs__name': '西安出版社'}]>
聚合查询、分组查询、F查询和Q查询
#聚合 #查询出所有图书的平均价格 #首先查询出数据,然后调aggregate这个方法里面传对应聚合函数,一旦调用了aggregate方法就不能调用queryset的方法,因为它返回的是字典 from django.db.models import Avg,Max,Min,Sum,Count avg_price = models.Book.objects.all().aggregate(Avg('price')) #{'price__avg': 30.883333} dict avg_price = models.Book.objects.all().aggregate(a=Avg('price')) #{'a': 30.883333} 可以给key起个别名 a print(avg_price)
#分组查询 :首先在values里面写要分组的字段,分组完成使用分组函数annotate里面写聚会函数,注意如果values里面写了多个值,并且后面annotate,就是按照values里面的最后一个值分组 # 查询每个出版社出版书的平均价格 from django.db.models import Avg, Max, Min, Sum, Count #方式1: avg_price = models.Book.objects.values('publishs_id').annotate(a=Avg('price')) #SELECT `app01_book`.`publishs_id`, AVG(`app01_book`.`price`) AS `a` FROM `app01_book` GROUP BY `app01_book`.`publishs_id` ORDER BY NULL LIMIT 21 # <QuerySet [{'publishs_id': 1, 'a': 53.2}, {'publishs_id': 2, 'a': 29.7}, {'publishs_id': 3, 'a': 21.5}]> print(avg_price) avg_price1 = models.Book.objects.values('publishs_id','nid').annotate(a=Avg('price')) print(avg_price1) #SELECT `app01_book`.`publishs_id`, `app01_book`.`nid`, AVG(`app01_book`.`price`) AS `a` FROM `app01_book` GROUP BY `app01_book`.`nid` ORDER BY NULL LIMIT 21; #<QuerySet [{'publishs_id': 3, 'nid': 1, 'a': 13.5}, {'publishs_id': 3, 'nid': 2, 'a': 29.5}, {'publishs_id': 1, 'nid': 3, 'a': 53.2}, {'publishs_id': 2, 'nid': 4, 'a': 43.5}, {'publishs_id': 2, 'nid': 7, 'a': 17.8}, {'publishs_id': 2, 'nid': 8, 'a': 27.8}]> #方式2:通过关联并且分组 ret = models.Publish.objects.annotate(a = Avg('book__price'))#<QuerySet [<Publish: Cc出版社>, <Publish: 新华出版社>, <Publish: 西安出版社>]> print(ret.values()) #<QuerySet [{'id': 3, 'name': 'Cc出版社', 'city': '南京', 'email': 'cy@163.com', 'a': 21.5}, {'id': 1, 'name': '新华出版社', 'city': '上海', 'email': '352@163.com', 'a': 53.2}, {'id': 2, 'name': '西安出版社', 'city': '西安', 'email': 'xian@qq.com', 'a': 29.7}]> print(ret.values('name','a')) #<QuerySet [{'name': 'Cc出版社', 'a': 21.5}, {'name': '新华出版社', 'a': 53.2}, {'name': '西安出版社', 'a': 29.7}]> ret1 = models.Publish.objects.annotate(a = Avg('book__price')).values('name','a') print(ret1) #分组后过滤 ret2 = models.Publish.objects.values('book__publishs_id').annotate(a= Avg('book__price')).values().filter(a__gt=22) print(ret2)
F查询与Q查询

浙公网安备 33010602011771号