跨表操作
跨表,基于QuerySet查询时,不用加set,使用神奇的双下划线'__'。values()和values_list()取值的时候也是。
tag_list=models.Tag.objects.filter(blog=blog).annotate(c=Count('article')).values('title','c')
BBS项目中:.annotate分组,前面是什么就表示以什么为分组,以某个博客的所有标签为分组对像。
annotate(c=Count('article')),聚合,这里用article,因为前面的到的是QuerySet对象,不用article_set。这里用的相当于article__id。
一、一对多跨表:
1.建表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from django.db import models 2 3 class UserInfo(models.Model): 4 username=models.CharField(max_length=32) 5 password=models.CharField(max_length=32) 6 ut=models.ForeignKey(to='UserType',on_delete=True) 7 class UserType(models.Model): 8 title=models.CharField(max_length=32)
2.插入数据:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #创建数据 2 models.UserType.objects.create(title='人事部') 3 models.UserType.objects.create(title='财务部') 4 models.UserType.objects.create(title='公关部') 5 6 models.UserInfo.objects.create(username='杨国伟',password='123',ut_id=1) 7 models.UserInfo.objects.create(username='石恩光',password='123',ut_id=1) 8 models.UserInfo.objects.create(username='钱博文',password='123',ut_id=3) 9 models.UserInfo.objects.create(username='杨理想',password='123',ut_id=2) 10 models.UserInfo.objects.create(username='周腾飞',password='123',ut_id=3)
3.正向跨表
UserInfo中有ForeignKey字段,从UserInfo到UserType是正向跨表,反之是反向跨表。
#三种不同取值方法的跨表操作
1 obj=models.UserInfo.objects.filter(id=1).first()#获取一个UserInfo对象。结果是一个object 2 print(obj) 3 print(obj.username,obj.password,obj.ut_id,obj.ut.title) 4 obj=models.UserInfo.objects.values('username','password','ut_id','ut__title')#结果是一个字典 5 print(obj) 6 obj=models.UserInfo.objects.values_list('username','password','ut_id','ut__title')#结果是一个元组 7 print(obj)
运行结果:
UserInfo object (1)
杨国伟 123 1 人事部
<QuerySet [{'username': '杨国伟', 'password': '123', 'ut_id': 1, 'ut__title': '人事部'}, {'username': '石恩光', 'password': '123', 'ut_id': 1, 'ut__title': '人事部'}, {'username': '钱博文', 'password': '123', 'ut_id': 3, 'ut__title': '公关部'}, {'username': '杨理想', 'password': '123', 'ut_id': 2, 'ut__title': '财务部'}, {'username': '周腾飞', 'password': '123', 'ut_id': 3, 'ut__title': '公关部'}]>
<QuerySet [('杨国伟', '123', 1, '人事部'), ('石恩光', '123', 1, '人事部'), ('钱博文', '123', 3, '公关部'), ('杨理想', '123', 2, '财务部'), ('周腾飞', '123', 3, '公关部')]>
4.反向跨表
obj.小写的表名_set
1 obj=models.UserType.objects.filter(id=1).first() 2 print(obj) 3 print(obj.userinfo_set.all()) 4 for item in obj.userinfo_set.all(): 5 print(item.username,item.password) 6 obj=models.UserType.objects.values('title','userinfo__username','userinfo__password') 7 print(obj) 8 obj = models.UserType.objects.values_list('title', 'userinfo__username', 'userinfo__password') 9 print(obj)
运行结果:
UserType object (1)
<QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (2)>]>
杨国伟 123
石恩光 123
<QuerySet [{'title': '人事部', 'userinfo__username': '杨国伟', 'userinfo__password': '123'}, {'title': '人事部', 'userinfo__username': '石恩光', 'userinfo__password': '123'}, {'title': '公关部', 'userinfo__username': '钱博文', 'userinfo__password': '123'}, {'title': '财务部', 'userinfo__username': '杨理想', 'userinfo__password': '123'}, {'title': '公关部', 'userinfo__username': '周腾飞', 'userinfo__password': '123'}]>
<QuerySet [('人事部', '杨国伟', '123'), ('人事部', '石恩光', '123'), ('公关部', '钱博文', '123'), ('财务部', '杨理想', '123'), ('公关部', '周腾飞', '123')]>
二、多对多
多对多,需要第三张表来建立关系。
技巧:
如果想从不含FK 的表中进行跨表,用object.小写表名_set.all()。小写的表名是含有FK的表。
从含FK的表中进行跨表,FK名__字段名。字段名是要跨到的那张表的字段名。
1.创建表
1 from django.db import models 2 3 class Boy(models.Model): 4 name=models.CharField(max_length=32) 6 class Girl(models.Model): 7 name=models.CharField(max_length=32) 8 class Love(models.Model): 9 b=models.ForeignKey('Boy',on_delete=True) 10 g=models.ForeignKey('Girl',on_delete=True)
方法一:
从不含FK的表进行跨表,_set.all()。得到Love对象。
obj=models.Boy.objects.filter(id=1).first() g_list=obj.love_set.all()#Love对象for item in g_list: print(item.g.name)
方法二:
从Love中进行跨表,__字段名。得到是Love对象。
1 obj_list=models.Love.objects.filter(b__id=1) 2 print(obj_list) 3 for item in obj_list: 4 print(item.g.name)
方法三:
上面的方发,每次循环都要去数据库查询,进行跨表操作。
此方法可避免,只进行一次查询,跨表。
obj_list=models.Love.objects.filter(b__id=1).values('g__name') for item in obj_list: print(item['g__name'])
补充:
创建联合唯一外键,表示Love表中,(b,q)只能出现一次。
class Love(models.Model): b=models.ForeignKey('Boy',on_delete=True) g=models.ForeignKey('Girl',on_delete=True) class Meta: unique_together=[ ('b', 'g'), ]
多对多之Django自动创建第三张表:
from django.db import models class Boy(models.Model): name=models.CharField(max_length=32) m=models.ManyToManyField('Girl')#也可以放在Girl中 class Girl(models.Model): name=models.CharField(max_length=32)
往Django自动创建的第三张表boy_m中添加数据。
由于后台并没有boy_m的类,所以不能用前面添加数据的方法。
obj=models.Boy.objects.filter(id=1).first() obj.m.add(1) obj.m.add(2,3)
这表示给id=1的boy和id=1,2,3的girl建立关系
obj=models.Boy.objects.filter(id=1).first() obj.m.remove(1)#删除id=1的boy和id=1的girl的关系 obj.m.remove(2,3)#同上
obj.m.add(1,2) obj.m.set([3])#重置关系,把原来的关系都删除了,然后自设置。
#把id=1的boy和id=1,2的girl的关系删除,然后建立id=1的boy和id=1的girl的关系
1 obj.m.add(1,2) 2 g_list=obj.m.all()#查看所有和id=1的boy有关的girl,得到的是Girl对象 3 print(g_list) 4 for item in g_list: 5 print(item.name)
obj.m.clear()#删除所有id=1的boy的关系
正向查询:
1 obj=models.Boy.objects.filter(id=1).first() 2 g_list=obj.m.all() 3 print(g_list) #Girl对象 4 for item in g_list: 5 print(item.name)
反向查询:
obj=models.Girl.objects.filter(id=2).first() obj_list=obj.boy_set.all() print(obj_list)#Boy对象 for item in obj_list: print(item.name)
多对多自动创建手动创建第三张表结合:
1 from django.db import models 2 3 class Boy(models.Model): 4 name=models.CharField(max_length=32) 5 m=models.ManyToManyField('Girl',through='Love',through_fields=('b','g')) 6 class Girl(models.Model): 7 name=models.CharField(max_length=32) 8 class Love(models.Model): 9 b=models.ForeignKey('Boy',on_delete=True) 10 g=models.ForeignKey('Girl',on_delete=True) 11 class Meta: 12 unique_together = [ 13 ('b', 'g'), 14 ]
m=models.ManyToManyField('Girl',through='Love',through_fields=('b','g'))。
表示同过Love表进行关联,关联的字段(b,g)。切不会自动生成表,会创建Love表。
其中:上面两种分开的操作,在这里都可以用
给Love表操作时:obj..m.add()/remove()/set()不可以用
clear(),all()可以用
多对多:自己关联自己。FK
对男女进行配对,现建一张表,自己关联自己。
建表的时候,U2U表中,表中第一列是b_id,填男生id,第二列是g_id,填女生id。不可填错,否则关系就出错了。
related_name:给所属的对象命名,因为是自己关联自己,查找是要知道是男生还是女生对象来查找。
男生对象.girl.all():就得到所有的和该男生有关的行,是U2U对象。用(.g.name)就得到女生的姓名。女生查找类似。
#测试自己关联自己 FK class UserInfo(models.Model): name=models.CharField(max_length=32) username=models.CharField(max_length=32) password=models.CharField(max_length=32) gender_choose=( (1,'男'), (2,'女'), ) gender=models.IntegerField(choices=gender_choose) class U2U(models.Model): b=models.ForeignKey('UserInfo',on_delete=True,related_name='girl') g=models.ForeignKey('UserInfo',on_delete=True,related_name='boy')
#找所有和该男生相关的女生 b_obj=models.UserInfo.objects.filter(id=1).first() g_list=b_obj.girl.all() print(g_list) for i in g_list: print(i.g.name,i.g.gender)
自己关联自己。M2M
这样创建表,django会自动生成以个关系表,出id列还有两列。你需要自己规定第一列填男生id还是女生id。这里规定,第一列男生id,第二列女生id。
这就相当于:一张男生表,一张女生表,男生表里有M2M。
则查询是就是:男生对象.m.all()
女生对想.userinfor_set.all()
#查找和该男生相关的所有女生 b_obj=models.UserInfo.objects.filter(id=1).first() g_list=b_obj.m.all() print(g_list) for i in g_list: print(i.name,i.gender) #查找和该女生相关的所有男生 g_obj=models.UserInfo.objects.filter(id=3).first() b_list=g_obj.userinfo_set.all() print(b_list) for i in b_list: print(i.name,i.gender)
class UserInfo(models.Model): name=models.CharField(max_length=32) username=models.CharField(max_length=32) password=models.CharField(max_length=32) gender_choose=( (1,'男'), (2,'女'), ) gender=models.IntegerField(choices=gender_choose) m=models.ManyToManyField('UserInfo')