Django模型三
关联对象操作及多表查询
关联表的数据操作:
一对多:
正向:如果一个模型有外键字段,通过这个模型对外键进行操作叫做正向。
更新:
通过属性赋值
In [1]: from teacher.models import Student In [2]: from teacher.models import Grade In [3]: g=Grade.objects.create(name='django框架',num='7') In [4]: g Out[4]: <Grade: Grade object (1)> In [5]: g=Grade.objects.first() In [6]: s=Student.objects.first() In [7]: s.grade=g In [8]: s.save()
通过主键的方式
In [9]: s2=Student.objects.last() In [10]: s2.grade_id=g.id In [11]: s2.save()
总结:Foreignkey字段的更新,跟普通字段没什么区别。
删:只有外键设置了null=True,你就可以通过赋值None来删除关系
In [15]: s.grade=None In [16]: s.save()
查:
In [18]: res=Student.objects.filter(grade__name='django框架') In [19]: print(res.query) SELECT `teacher_student`.`id`, `teacher_student`.`name`, `teacher_student`.`age`, `teacher_student`.`sex`, `teacher_student`.`qq`, `teacher_student`.`phone`, `teacher_student`.`c_time`, `teacher_student`.`grade_id` FROM `teacher_student` INNER JOIN `teacher_grade` ON (`teacher_student`.`grade_id` = `teacher_grade`.`id`) WHERE `teacher_grade`.`name` = django框架
过滤Foreignkey字段模型的字段
反向:一个模型如果被另外一个模型外键关联,通过这个模型对关联它的模型进行操作叫做反向。
查:通过管理器,默认管理器是有外键的模型名称的小写加上_set(foo_set,foo是模型名称小写),通过这个管理器可以查询模型的实例,在定义外键的时候,通过related_name可以覆盖这个名称。
grade=models.ForeignKey('Grade',on_delete=models.SET_NULL,null=True,related_name='students1') In [2]: from teacher.models import Grade,Student In [3]: g=Grade.objects.first() In [4]: g Out[4]: <Grade: django框架> In [6]: g.students1.all() Out[6]: <QuerySet [<Student: 赵柳>]>
增:
通过add方法,可以添加多个
In [11]: new_s=Student.objects.first()
In [13]: g.students1.add(new_s)
In [17]: s1=Student.objects.get(pk=2)
In [18]: s2=Student.objects.get(pk=3)
In [19]: g.students1.add(s1,s2)
通过create方法
In [22]: g.students1.create(name='郭富城') Out[22]: <Student: 郭富城>
删:删掉关系
remove(obj1,obj2,obj3)
In [23]: gfc=Student.objects.last() In [24]: g.students1.remove(gfc)
clear() 清空
In [25]: g.students1.clear()
add,remove,clear直接操作数据库
改:替换对象集
set([s1,s2])
In [25]: s1 Out[25]: <Student: 李四> In [26]: s2 Out[26]: <Student: 王五> In [27]: g.students1.set([s1,s2])
多对多:
如果因为有额外字段,自定义了中间模型,我们就需要通过中间模型的管理器进行manytomany关系的创建和删除
默认情况跟一对多中的add,create,remove,clear用法一致
唯一的区别是多对多正向的时候,多对多字段就是一个管理器。
反向的时候,跟一对多的方向一致,也是在模型小写后面加上_set,和一对多类似,一样可以通过定义related_name可以覆盖这个名称。
In [1]: from teacher.models import Course,Enroll In [2]: c1=Course.objects.create(name='python全栈') In [4]: c2=Course.objects.create(name='python全套') In [10]: from teacher.models import Course,Enroll,Student In [11]: s1=Student.objects.create(name='范冰冰') In [12]: s2=Student.objects.create(name='李冰冰') In [13]: s1 Out[13]: <Student: 范冰冰> In [14]: s2 Out[14]: <Student: 李冰冰> In [15]: e=Enroll() In [16]: e.student=s1 In [17]: e.course=c1 In [18]: e.paid=6680 In [19]: e.save() In [20]: c1 Out[20]: <Course: python全栈> In [21]: c1.students.all() Out[21]: <QuerySet [<Student: 范冰冰>]> In [22]: c1.students.filter(name='范冰冰') Out[22]: <QuerySet [<Student: 范冰冰>]> In [23]: c1.students.get(name='范冰冰') 、Out[23]: <Student: 范冰冰> In [24]: s1 Out[24]: <Student: 范冰冰> In [25]: s1.course_set.filter(name__startswith='python') Out[25]: <QuerySet [<Course: python全栈>]>
一对一:
非常类似一对多字段,增删改查和普通字段没有什么区别
反向的时候,使用模型的小写,也可以给related_name覆盖,这个就不是管理器,就是一个普通属性。
注意:一个被一对一管理的模型,他的实例如果没有被分配关系。举个例子:学生对象,没有分配一个学生详情对象。如果去取,全抛出异常DoseNotExist。
跨表查询: 要跨越关系,只需使用跨越模型的相关字段名,以下划线分隔,直到达到你想要的字段为止。
例如:查询男生都报名了什么课程
res=Course.objects.filter(students__sex=1).distinct()
这个关系要多深就有多深
例:查询所有报名了python课的学员
res=Student.objects.filter(course__name__contains='python')
例:查询所有报名python全栈课程,在django框架第七期班级的学员
res=Student.objects.filter(course__name='python全栈',grade__name='django框架',grade__num='7')
例:学员报名了python课程的班级有哪些
res=Grade.objects.filter(students1__course__name__contains='python').distinct()