[django] 表关联对象及多表查询

匿名 (未验证) 提交于 2019-12-02 23:52:01

表关联对象及多表查询

关系表的数据操作

前面我们在models.py文件中创建了一些关系表 , 接下来我们就来操作这写表里的数据

为了能方便学习,我们进入项目的idle中去执行我们的操作,
通过控制台输入python manage.py shell 就能进入当前目录下的IDLE

导入关系表

from firstapp.models import Student, StudentDetail, Grade, Course, Enroll   

设置__str__

通过设置str方法可以使我们在查询某个模型对象的时候, 直观的看到其简要内容, 例如, id和name等:

def __str__(self):     return '{}-{}'.format(self.name, self.num) 

表关联对象的访问

相互关联的表之间的访问方式分为 正向 和 反向 , 下面我们来详细了解一下

什么是正向or反向?

ForeignKey/OneToManyField/ManyToManyField这种类型的字段为参照物, 凡是担有这种字段的表 , 通过其来访问这个外键链接的表, 这种方式就是正向访问 , 反过来就是反向访问

OneToMany 正向

正向:一个模型如果有外键字段,通过这个模型对外键进行操作叫做正向(eg:student模型有grade外键字段) 
反向:一个模型如果被另一个模型外键关联,通过这个模型对关联它的模型进行操作叫做反向(eg:grade模型被student模型的grade外键关联,通过grade对student进行操作) 

增&改

正向的增和改是一样的,

通过属性赋值的方式
In [19]: g1=Grade.objects.get(name='django框架') In [20]: s1 = Student.objects.get(name='Jack') In [21]: s1.grade = g1 In [22]: s1.save() # s1 -> g1 , 将学生Jack(s1)分到django框架班(s2)中, 学生表中的`grade_id`变为了'django框架'的班级id 
通过主键的方式
In [24]: g2=Grade.objects.get(name='python爬虫基础') In [26]: s2 = Student.objects.get(name='Jennf') In [28]: s2.grade_id = g2.id In [29]: s2.save()   # s2 -> g2 , 与上同理 

改的方式是一样的, 通过赋值来完成改操作

In [35]: s2.grade_id = g1.id	 In [36]: s2.save()    # s2 -> g1 , 学生Jennf(s2)被改到django框架(g1)班 

In [3]: s1.grade	# 可以直接获取grade对象, 这里设置了__str__方法所以才这样显示 Out[3]: <Grade: django框架-8>  In [4]: s1.grade.name	# 也可以通过获取对象的属性,这就涉及到了联合查询 Out[4]: 'django框架' # 联合查询 In [5]: Student.objects.filter(grade__name='django框架')   Out[38]: <QuerySet [<Student: Micker>, <Student: Jack>, <Student: Jennf>]> # 外键字段对象的属性可以通过两个下划线来获取 

ɾ

In [39]: s1.grade = None In [40]: s1.save()    

OneToMany 反向

上面的正向增删改查用到的管理器对象是objects , 而反向则与其不同 , 反向的增删改查用的管理器是 app小写名_set来操作, 例如, g2.student__set.all()

# 实际访问情况:如果一个模型有外键(eg:student模型),那么这个外键模型的实例(eg:grade模型的实例g2)将可以通过一个管理器(返回的是Student模型的所有实例的管理器),默认情况下管理名为(student_set),其中student是源模型名,小写。 

如果觉得student_set使用麻烦, 也可以用这个related_name='student'重命名 , 之后就可以用student来访问了, 如下设置在Student的外键中

grade = models.ForeignKey('Grade', on_delete=models.SET_NULL, null=True, related_name='student') 

In [2]: g1=Grade.objects.get(name='django框架') In [4]: new_student = g1.student_set.create(name='Fet', age=17, sex=0)  # new_student -> g1 , 为django框架(g1)创建一个新的学生Fet 
批量增
In [18]: s1,s2,s3 = Student.objects.filter(id__lte=3) In [19]: g1.student_set.add(s1,s2,s3) # 通过add传入多个对象, 即可实现批量增加 

In [9]: g1.student_set.set([s1,s2])   # g1(s1,s3,s5) -> g1(s1,s2) , 会将django框架(g1)班中的人替换为s1和s2两人 

ɾ

In [20]: g1.student_set.remove(s1)	# 指定删除 In [21]: g1.student_set.clear()  # 全部删除 

查的方法和普通查询类似 , 这里就不再赘述

In [10]: g1.student_set.all() Out[10]: <QuerySet [<Student: Micker>, <Student: Jack>]>  In [12]: g1.student_set.filter(name='Micker') Out[12]: <QuerySet [<Student: Micker>]> 

ManyToMany

基于以字段为参照物的准则 , 这里的正向是从Course -> Student , Course模型:

class Course(models.Model):     name = models.CharField('课程名', max_length=20)     student = models.ManyToManyField("Student", through='Enroll') 

Course里面有ManyToManyField字段,模型在正向访问时就使用该字段本身的属性名student, 而不是student_set (这里注意student是自定义的)

# 创建连接 In [5]: s1 = Student.objects.get(pk=1) In [6]: c1 = Course.objects.create(name='Python基础') In [8]: e = Enroll() In [9]: e.course = c1 In [11]: e.student = s1 In [12]: e.save()  

正向查询

In [15]: c1.student.all() Out[15]: <QuerySet [<Student: Micker>]> 

反向查询

在反向访问时使用的属性名是, 原始模型的小写模型名加上_set, 即course_set

In [21]: s1.course_set.all() Out[21]: <QuerySet [<Course: Python基础>]> 

OneToOne

正向

通过属性访问

In [17]: d1 = StudentDetail(college = '潭州大学') In [18]: d1.student = s1 In [19]: d1.save() # 这就完成了正向操作 

反向

通过原始模型的小写模型名访问

In [10]: d2 = StudentDetail(college='清华大学') In [11]: s2 = Student.objects.get(pk=2) In [12]: s2.studentdetail = d2 In [13]: s2.save()  

多表查询

正向查询 当表进行关联后 , 就可以通过 StudentDetail 直接访问到 Student的内容

In [16]: StudentDetail.objects.values('college', 'student__name')      Out[16]: <QuerySet [{'college': '北京大学', 'student__name': 'Jesse'}, {'college': '清华大学', 'student__name': 'Jack'}]> 

通过这种双下滑线的方式, 可以获得student中所有的属性

反向查询 同样适用

In [17]: Student.objects.values('name', 'studentdetail__college')                                                                                Out[17]: <QuerySet [{'name': 'Jesse', 'studentdetail__college': '北京大学'}, {'name': 'Jack', 'studentdetail__college': '清华大学'}]> 

使用这种查询可以完成更深的数据挖掘(仅在当前数据库内)

Course.objects.filter(student__sex=1)  # 男生报了什么课程  Student.objects.filter(course__name='python') # 报了’python‘的学生  Student.objects.filter(course__name='python',grade__num='8') # 所有报了python,8期的学员  Student.objects.filter(enroll__pay__lt=3000) # 缴费小于3000的学员  Grade.objects.filter(student__course__name = 'python').distinct()  # 学员报名Python课程的班级有哪些。distinct()去重 
文章来源: https://blog.csdn.net/makesomethings/article/details/90546472
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!