文章目录
前言
已知学生表、学生详情表、课程表、报名表、渠道表;
其中学生表和学生详情表的关联关系为一对一;
学生表和课程表的关系为多对多;
学生表和渠道表的关系为一对多;
一、级联操作
on_delete=models.CASCADE:当父表数据删除时,相对应的从表数据会自动删除
on_delete=models.SET_NULL:当父表数据删除时,相对应的从表数据会自动设置为null
on_delete=models.PROTECT:当父表数据删除时,如果有相对应从表数据会抛出异常
on_delete=models.SET_DEFAULT:当父表数据删除时,相对应的从表数据会被自动设置为默认值,还需要额外指定default=True
注意:外键字段必须指定on_delete参数
二、一对多(多对一)的关联模型类设计
在django中要表达多对一的关系需要用到ForeignKey。
以学生模型类(Student)和渠道模型类(Channel)为案例:
学生表中定义外键
注意1:外键字段要定义在多的一方,这个字段名使用关系模型类的小写名字,所以Student模型中定义一个channel字段.
注意2:外键字段的第一个参数是一个位置参数,即需要关联的模型,可以是模型本身,也可以是模型的字符串形式的导路径(当引用后定义的模型的时候很有用),一般使用也可以是模型的字符串形式的导路径
注意3:在数据库层面,django会在外键字段名后附加_id来创建数据库列名,所以Student模型类的数据表将有一个channel_id的列,然后会为这个列创建一个外键约束,被引用的表为t_channel,被引用的字段为t_channel.id
在当前案例中,删除一个渠道时,渠道下的学生不应该删除,所以外键的级联操作为on_delete=models.SET_NULL
1、学生表模型类设计
**默认每一个模型都会自动生成一个主键,所以id主键可以不写
如果写:id = models.AutoField(primary_key=True, verbose_name='主键',help_text='主键')
**
null=True和blank=True的区别:
null=True:表示的数据库层面的,代表数据库中该字段可以为空
blank=True:表示反序列化输入的时候可以为空
null和blank一般是成对出现的
classStudent(models.Model):
name = models.CharField(help_text='学生姓名',
verbose_name='学生姓名',
max_length=128)
age = models.SmallIntegerField(help_text='年龄',
verbose_name='年龄',
null=True,
blank=True)#todo null和blank一般是成对出现的
sex = models.SmallIntegerField(help_text='性别',
verbose_name='性别',
default=1),
phone = models.CharField(help_text='手机号码',
verbose_name='手机号码',
unique=True,
max_length=11,
blank=True,
null=True)
address=models.CharField(help_text='家庭住址',
verbose_name='家庭住址',
unique=True,
max_length=128,
blank=True,
null=True)
create_time = models.DateTimeField(help_text='创建时间',
verbose_name='创建时间',
auto_now_add=True)
channel=models.ForeignKey('Channel',
on_delete=models.RESTRICT,
null=True,
help_text='外键字段')#不允许删除classMeta:
db_table="t_student"#指定生成数据库表的名称,如果不定义则自动生成crm_student
verbose_name='学生表'
verbose_name_plural=verbose_name #在django-admin中模型的名字
ordering=['id']#排序def__str__(self):return self.name
2、渠道表模型类设计
classChannel(models.Model):
name=models.CharField(help_text='渠道名称',
verbose_name='渠道名称',
unique=True,
max_length=128)classMeta:
db_table='t_channel'
verbose_name='渠道表'
verbose_name_plural=verbose_name
def__str__(self):return self.name
classCourse(models.Model):
name=models.CharField(help_text='课程名称',
verbose_name='课程名称',
unique=True,
max_length=128)
students=models.ManyToManyField('Student',
help_text='报名学生',
verbose_name='报名学生')classMeta:
db_table ='t_course'
verbose_name ='课程表'
verbose_name_plural = verbose_name
def__str__(self):return self.name
三、多对多的关联模型类设计
在django中要表达多对多的关系需要用到ManyToManyField字段
学生表和课程表是多对多的关系
注意1:多对多字段一般来说会定义在需要在表单中编辑的对象中,或者是业务中需要查询更多的模型中
在我们的案例中,编辑学生对象,或者编辑课程对象都不需要彼此,而在查询"报名的某个课程的学生有那些?",这个需求会更多,所以把多对多的字段定义在课程表中
注意2:多对多关联字段里一般设置为关系模型的复数形式,表示关系模型的对象集,所以Course模型中的多对多字段名为students
注意3:多对多字段的第一个参数是位置参数,和外键字段一样
注意4:在数据库层面,多对多的字段并不会在数据库表中创建对应的字段,而是django会自动创建一个中间表来表示多对多的关联关系。
默认情况下这个中间表的表名使用创建多对多字段的模型的表名+_+多对多字段名,所以案例中的第三张中间表为t_course_students
注意5:第三张表分别包含2个字段,分别是两个关系模型的小写名+_id组成(student_id course_id),并且创建外键应用对应表的id,还会对这2个字段创建一个联合唯一的索引
1、课程表模型类设计
classCourse(models.Model):
name=models.CharField(help_text='课程名称',
verbose_name='课程名称',
unique=True,
max_length=128)
students=models.ManyToManyField('Student',
help_text='报名学生',
verbose_name='报名学生')classMeta:
db_table ='t_course'
verbose_name ='课程表'
verbose_name_plural = verbose_name
def__str__(self):return self.name
四、多对多的关联模型类设计(自定义中间表)
虽然django会自定义第三张中间表,但是不能提供额外的字段,如果中间表需要包含其他字段,就需要自定义中间表,然后在定义多对多字段的时候,通过through参数指定第三张中间表
**
students = models.ManyToManyField('Student',help_text='报名学生',verbose_name='报名学生',through='Entry')
**
Entry模型类中,字段student和course都是外键,分别引用Student模型、Course模型,表达这2个模型的多对多关系
1、模型类设计
课程表模型类设计
classCourse(models.Model):
name = models.CharField(help_text='课程名称',
verbose_name='课程名称',
unique=True,
max_length=128)
students = models.ManyToManyField('Student',
help_text='报名学生',
verbose_name='报名学生',
through='Entry')classMeta:
db_table ='t_course'
verbose_name ='课程表'
verbose_name_plural = verbose_name
def__str__(self):return self.name
报名表模型类设计
classEntry(models.Model):
student = models.ForeignKey('Student',
verbose_name='学生',
help_text='学生',
on_delete=models.PROTECT)
course = models.ForeignKey('Course',
help_text='课程',
verbose_name='课程',
on_delete=models.PROTECT)
create_time = models.DateTimeField(help_text='报名时间',
verbose_name='报名时间',
auto_now_add=True)classMeta:
db_table ='t_entry'
verbose_name ='报名表'
verbose_name_plural = verbose_name
def__str__(self):returnf'{self.student.name}报名了{self.course.name}课程'
2、数据表字段
3、数据表结构
数据库迁移后django不会自动创建这两个外键的联合唯一索引
如果有需要,需要手动创建,在Meta类中添加如下代码
**
constraints=[UniqueConstraint(fields('student','course'),name='student_course_unique') ]
**
classEntry(models.Model):
student = models.ForeignKey('Student',
verbose_name='学生',
help_text='学生',
on_delete=models.PROTECT)
course = models.ForeignKey('Course',
help_text='课程',
verbose_name='课程',
on_delete=models.PROTECT)
create_time = models.DateTimeField(help_text='报名时间',
verbose_name='报名时间',
auto_now_add=True)classMeta:
db_table ='t_entry'
verbose_name ='报名表'
verbose_name_plural = verbose_name
#todo 多字段联合唯一索引
constraints=[
UniqueConstraint(fields=('student','course'),name='student_course_unique')]def__str__(self):returnf'{self.student.name}报名了{self.course.name}课程'
数据表结构
五、一对一的关联模型类设计
在django中要表达多对多的关系需要用到OneToOneField字段
学生表和学生详情表的关系为一对一的关系,创建学习详情模型表如下
1、模型类设计
classStudentDetail(models.Model):
STATION_CHOICES =[('java','java'),('python','python'),('测试开发','测试开发'),('运维','运维')]
SALARY_CHOICES =[('5000以下','5000以下'),('10000-15000','10000-15000'),('15000-20000','15000-20000'),('20000以上','20000以上')]
student = models.OneToOneField('Student',
verbose_name='学生详情',
help_text='学生详情',
on_delete=models.CASCADE)
city = models.CharField(help_text='所在城市',
verbose_name='所在城市',
max_length=128,
null=True,
blank=True)
company = models.CharField(help_text='所在单位',
verbose_name='所在单位',
max_length=128,
null=True,
blank=True)
station = models.CharField(help_text='岗位',
verbose_name='岗位',
max_length=128,
choices=STATION_CHOICES,
null=True,
blank=True,
default='测试开发')
salary=models.CharField(help_text='薪资',
verbose_name='薪资',
null=True,
blank=True,
choices=SALARY_CHOICES,
max_length=20,
default='20000以上')classMeta:
db_table ='t_student_detail'
verbose_name ='学生详情表'
verbose_name_plural = verbose_name
def__str__(self):return self.student.name
2、数据表结构
在数据库层面,会创建一个student_id的列,然后为这个列创建一个外键约束,引用表为t_student,字段为t_student.id
与多对一不同,这个列还会创建一个唯一约束,形成一对一的关系,其他的级联操作与多对一一样
3、数据表字段
版权归原作者 敲代码敲到头发茂密 所有, 如有侵权,请联系我们删除。