表关系实现
1. 表关系的创建
- OneToOne 创建一个学生详情表StudentDetail,与Student表一对一关系
student = models.OneToOneField('Student', on_delete=models.CASCADE)
- OneToMany
grade = models.ForeignKey('Grade', on_delete=models.SET_NULL, null=True)
- ManyToMany
学生表(Student)与课程表(Course)之间是多对多的关系,通过中间表关联。中间表分别去外键关联,并且联合唯一
详细model.py如下:
from django.db import models # Create your models here. class Student(models.Model): name = models.CharField(max_length=20) age = models.SmallIntegerField(default=0) sex = models.SmallIntegerField(default=1) qq = models.CharField(max_length=20,unique=True,null=True) phone = models.CharField(max_length=20,unique=True,null=True) #删除年级的时候不必把学生都删除,必须可以设置年级字段为null,on_delete=models.SET_NULL,null=True grade = models.ForeignKey('Grade',on_delete=models.SET_NULL,null=True) #一对多关系,与Grade是多对一的关系 c_time = models.DateTimeField(verbose_name='创建时间',auto_now_add=True) e_time = models.DateTimeField(verbose_name='编辑时间',auto_now=True) is_deleted = models.BooleanField(default=False) def __str__(self): return '%s-%s-%s' %(self.id,self.name,self.age) class StudentDetail(models.Model): num = models.CharField(max_length=20,default="") college = models.CharField(max_length=20,default="") #如果把学生删除了,学生详情里面的也要删除on_delete=models.CASCADE(级联操作,保证一直) student = models.OneToOneField('Student',on_delete=models.CASCADE) #与Student表一对一关系,‘Student’字符串更加通用,无论Student模型是在前面后者后面都能使用 class Grade(models.Model): name = models.CharField(max_length=20) num = models.CharField(max_length=20) def __str__(self): return '%s - %s' %(self.num,self.name) class Course(models.Model): name = models.CharField('课程名称',max_length=20) students = models.ManyToManyField('Student',through='Enroll')#与学生是多对多,如果中间表只有两个表的id,则不需要主动创建中间表Enroll,系统自动创建中间表teacher_course_students def __str__(self): #如果第三张表中有额外的字段,需要手动创建中间表Enroll return self.name class Enroll(models.Model): #中间表为报名表 student = models.ForeignKey('Student',on_delete=models.CASCADE) #中间表分别去外键关联,并且联合唯一 course = models.ForeignKey('Course',on_delete=models.CASCADE) pay = models.FloatField('缴费金额',default=0) c_time = models.DateTimeField('报名时间',auto_now_add=True)
2. 关联表的数据操作
一对多关系操作
- OneToMany
- 正向: 一个模型如果定义了一个外键字段,通过这个模型操作外键
增删改查
导入模型,并查看已经创建的数据表数据
In [2]: from teacher.models import Student,StudentDetail,Course,Enroll,Grade In [3]: Grade.objects.all() Out[3]: <QuerySet [<Grade: 33期 - django框架>, <Grade: 34期 - 爬虫>]> In [4]: Student.objects.all() Out[4]: <QuerySet [<Student: 1-心蓝-0>, <Student: 2-litao-0>]>
正向增加的两种方法:
#1.第一种 通过直接赋值一个已经保存的对象给她
In [5]: s= Student() In [6]: s.name='梦洁' In [7]: g1 = Grade.objects.first() #g1为Grade的对象 In [8]: s.grade = g1 #Grade表必须先创建,不然保存不能成功 In [9]: s.save() In [10]: Student.objects.all() Out[10]: <QuerySet [<Student: 1-心蓝-0>, <Student: 2-litao-0>, <Student: 3-梦洁-0>]>
#2.第二种。赋值给他一个已经保存的Id给他
In [11]: s2 = Student(name = '魏明凯') In [12]: g2 = Grade.objects.last() In [13]: s2.grade_id =g2.id In [14]: s2.save() #Grade必须首先创建 In [15]: Student.objects.all() Out[15]: <QuerySet [<Student: 1-心蓝-0>, <Student: 2-litao-0>, <Student: 3-梦洁-0>, <Student: 4-魏明凯-0>]>
正向更新修改:
In [34]: Student.objects.all() Out[34]: <QuerySet [<Student: 1-心蓝-0>, <Student: 2-litao-0>, <Student: 3-梦洁-0>, <Student: 4-魏明凯-0>, <Student: 5-litao-0>]> In [35]: s2= Student.objects.get(id=2) In [36]: s2 Out[36]: <Student: 2-litao-0> In [37]: s1= Grade.objects.first() In [38]: s2.grade=s1 In [39]: s2.save()
正向删除:
删除外键时候定义必须有一个None
grade = models.ForeignKey('Grade',on_delete=models.SET_NULL,null=True)
In [41]: s= Student.objects.first() In [42]: s Out[42]: <Student: 1-心蓝-0> In [43]: s.grade= None In [44]: s.save()
正向查:
通过学生表的查询学生所在班级的名称,班级
In [41]: s= Student.objects.first() In [49]: s.grade.name Out[49]: 'django框架' In [50]: s.grade.num Out[50]: '33期'
反向:
从Grade的对象反过来查和它 关联的student的模型
一个模型如果被另外一个模型外键关联,通过这个模型去对关联它的模型进行操作就叫反向
反向增加
1.直接创建,增加
In [53]: g3 =Grade.objects.create(name='进阶',num='40期') #反向,g3.反向关联字表的小写_set 操作 In [54]: g3.student_set.create(name='刘洋') Out[54]: <Student: 6-刘洋-0> #2.将已经存在的对象添加到g3,add,create都是立刻执行,不需要save() In [55]: s Out[55]: <Student: 1-心蓝-0> In [56]: g3.student_set.add(s)
反向查询
In [81]: g3.student_set.all() Out[81]: <QuerySet [<Student: 1-心蓝-0>, <Student: 2-litao-0>, <Student: 6-刘洋-0>]> In [82]: s3.grade Out[82]: <Grade: 40期 - 进阶>
反向修改更新:
#s3 本来是33期,通过反向查询将其修改为40期 #add方法可以添加多个对象#g3.student_set.add(s3,s2,s1) In [78]: s3 = Student.objects.get(id=2) In [79]: s3.grade Out[79]: <Grade: 33期 - django框架> In [80]: g3.student_set.add(s3)
反向删除:
In [89]: g3.student_set.all() Out[89]: <QuerySet [<Student: 1-心蓝-0>, <Student: 2-litao-0>, <Student: 6-刘洋-0>]> In [90]: s.name Out[90]: '心蓝' In [91]: g3.student_set.remove(s) In [92]: g3.student_set.all() Out[92]: <QuerySet [<Student: 2-litao-0>, <Student: 6-刘洋-0>]>
反向清除:clear
In [95]: g3.student_set.all() Out[95]: <QuerySet [<Student: 2-litao-0>, <Student: 6-刘洋-0>]> In [96]: g3.student_set.clear() In [97]: g3.student_set.all() Out[97]: <QuerySet []>
反向修改重置:
In [98]: s Out[98]: <Student: 1-心蓝-0> In [100]: s1= Student.objects.get(id=2) In [101]: g3.student_set.set([s,s1]) #接受一个列表,先调用clear,在添加add。如果没有clear再执行add
查询student 表中所有的django框架的学生
In [109]: res = Student.objects.filter(grade__name='django框架') #关联字段用'__'
In [110]: print(res.query) SELECT `teacher_student`.`id`, `teacher_student`.`name`, `teacher_student`.`age`, `teacher_student`.`sex`, `teacher_student`.`qq`, `teacher_student`.`phone`, `teacher_student`.`grade_id`, `teacher_student`.`c_time`, `teacher_student`.`e_time` FROM `teacher_student` INNER JOIN `teacher_grade` ON (`teacher_student`.`grade_id` = `teacher_grade`.`id`) WHERE `teacher_grade`.`name` = django框架