骄傲的赛亚人

day6-django-表关系

表关系

多对一

在django中要表达多对一的关系需要使用django.db.models.ForeignKeyField字段。报名表,学生表,课程表,课程顾问表,是多对一的关系

 

 1 class Student(models.Model):  # 必须继承
 2     """
 3     每个字段实例的名称,类属性名称,就是数据库字段的名称
 4     """
 5     name = models.CharField(verbose_name="姓名", max_length=20, help_text="姓名")
 6     age = models.SmallIntegerField("年龄", null=True, blank=True, help_text="年龄")
 7     sex = models.SmallIntegerField("性别", default=1, help_text="性别")
 8     qq = models.CharField("qq号码", max_length=20, null=True, blank=True, unique=True, help_text="qq号码")
 9     phone = models.CharField("手机号码", max_length=20, null=True, blank=True, unique=True, help_text="手机号码")
10     channel = models.ForeignKey('Channel', on_delete=models.SET_NULL, null=True, verbose_name='渠道', help_text='渠道来源',
11                                 related_name='students')
12     c_time = models.DateTimeField("创建时间", auto_now_add=True)
13 
14     def __str__(self):
15         """打印字符串输出的名字"""
16         return self.name
17 
18     class Meta:
19         db_table = "tb_student"  # 设置创建表的表名
20         verbose_name = "学生信息"
21         verbose_name_plural = verbose_name  # django admin中显示模型的说明
22         ordering = ["age"]  # 根据年龄排序从小到大
23 
24 
25 class Course(models.Model):
26     name = models.CharField("课程名称", max_length=24, help_text="课程名称", unique=True)
27     price = models.IntegerField("价格", help_text="课程价格")
28     period = models.SmallIntegerField("课时", help_text="课时,以小时为单位")
29     students = models.ManyToManyField(Student, through="Entry", verbose_name="学生", help_text="报名课程的学生")
30 
31     def __str__(self):
32         return self.name
33 
34     class Meta:
35         db_table = "tb_course"
36         verbose_name = "课程表"
37         verbose_name_plural = verbose_name
38 
39 
40 class Entry(models.Model):
41     student = models.ForeignKey(Student, verbose_name="学生", help_text="报名学生", on_delete=models.PROTECT)
42     course = models.ForeignKey('Course', verbose_name="课程", help_text="报名课程", on_delete=models.PROTECT)
43     c_time = models.DateTimeField("报名时间", auto_now_add=True, help_text="报名时间")
44 
45     def __str__(self):
46         return "{}-{}".format(self.student.name, self.course.name)
47 
48     class Meta:
49         db_table = "tb_entry"
50         verbose_name = "报名表"
51         verbose_name_plural = verbose_name
52         constraints = [
53             UniqueConstraint(fields=['student', 'course'], name="unique_student_course")
54         ]
View Code
  1.  一般外键字段定义在多的一方
  2. 外键字段的第一个参数是一个位置参数,就是要关联的模型,可以是模型类本身,也可以是字符串形式的导入路径,当引用其它应用的模型,和引入后定义的模型时有用
    1.   外键引入models.ForeignKey(Student,....),models.ForeignKey('Student',....)关联表可以是一个模型类,也可以用字符串导入的方式
  3. 在数据库层面,django会在字段名的后面附加_id来创建数据库列名。例如上面例子中Entry模型的数据库将有一个student_id列,然后为这个列创建一个外键约束
  4. 注意:有时候为了效率,在数据库不会创建外键,而是通过代码逻辑来保证数据的完整性,可以通过ForeignKey字段中置顶db_constraint= False来控制不创建外键约束

级联操作

当一个由ForeignKey引用的对象被删除时,django将模拟on_delete参数指定的SQL约束行为

on_delete的可能值有:

  1. CASCADE:级联删除
  2. PROTECT:通过引发protectedErro防止删除被引用字段
  3. RESTRICT:通过引发restrictErro防止删除被引用字段
  4. SET_NULL:设置外键为空,只有当null=true才可以

注意:ForeignKey字段必须指定on_delete

 

一对一

在django中要表达一对一的关系需要使用django.db.models.OneToOneField字段,在crm中学生表和学生详情表就是一对一关系

 1 class StudentDetail(models.Model):
 2     # 下拉框定义方式一
 3     STATION_CHOICES = [
 4         ("功能测试工程师", "功能测试工程师"),
 5         ("自动化测试工程师", "自动化测试工程师"),
 6         ("测试开发工程师", "测试开发工程师"),
 7         ("测试组长", "测试组长"),
 8         ("测试经理", "测试经理"),
 9     ]
10 
11     # 下拉框定义方式二
12     class SalaryChoice(models.TextChoices):
13         FIRST = "5000以下", "5000以下",
14         SECOND = "5000-10000", "5000-10000"
15         THIRD = "10000-15000", "10000-15000"
16         FOURTH = "15000-20000", "15000-20000"
17         FIFTH = "20000以上", "20000以上"
18 
19     student = models.OneToOneField(Student, verbose_name="学生", on_delete=models.CASCADE, help_text="学生", null=True)
20     city = models.CharField("所在城市", max_length=24, help_text="所在城市", null=True, blank=True)
21     company = models.CharField("任职公司", max_length=48, help_text="任职公司", null=True, blank=True)
22     # 下拉框选择方式一
23     station = models.CharField("岗位", max_length=24, help_text="岗位", choices=STATION_CHOICES, default="功能测试工程师")
24     # 下拉框选择方式二
25     salary = models.CharField("薪资", max_length=24, help_text="薪资区间", choices=SalaryChoice.choices, default=SalaryChoice.SECOND)
26 
27     def __str__(self):
28         return self.student.name
29 
30     class Meta:
31         db_table = "tb_student_detail"
32         verbose_name = "学生详情表"
33         verbose_name_plural = verbose_name
View Code

 多对多

在django中要表达一对一的关系需要使用django.db.models.ManyToManyField字段

 

  1. 建议设置多对多字段名为一个复数名词,表示所要管理的模型对象的集合。
  2. 多对多关联的两个模型,可以在任何一个模型中添加多对多字段,但是只能选择一个模型设置,即不能在两个模型里都添加。
  3. 一般来讲,应该把多对多字段放到需要在表单中编辑的对象里。跟业务相关,具体情况具体对待。
  4. 在数据库层面,django会自动创建一张中间表来表示多对多的关系。默认情况下,这个表名是使用多对多字段的名字和包含它的模型名生成(上面的例子,会生成pizza_toppins),然后包含两个字段,分别是以两个关系模型的名字和_id组成(pizza_id,topping_id),并创建外键引用对应的表的id。

自定义中间表

当表示多对多关系的中间表需要包含其它字段的时候,需要自定义中间表,然后再定义多对多字段的时候,通过through参数指定第三张表,

 1 class Course(models.Model):
 2     name = models.CharField("课程名称", max_length=24, help_text="课程名称", unique=True)
 3     price = models.IntegerField("价格", help_text="课程价格")
 4     period = models.SmallIntegerField("课时", help_text="课时,以小时为单位")
 5     students = models.ManyToManyField(Student, through="Entry", verbose_name="学生", help_text="报名课程的学生")
 6 
 7     def __str__(self):
 8         return self.name
 9 
10     class Meta:
11         db_table = "tb_course"
12         verbose_name = "课程表"
13         verbose_name_plural = verbose_name
View Code

 

posted on 2022-06-10 10:36  骄傲的赛亚人  阅读(33)  评论(0编辑  收藏  举报

导航