0


【django】各种关联关系的模型类设计

在这里插入图片描述


文章目录

前言

已知学生表、学生详情表、课程表、报名表、渠道表;
其中学生表和学生详情表的关联关系为一对一;
学生表和课程表的关系为多对多;
学生表和渠道表的关系为一对多;

一、级联操作

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、数据表字段

在这里插入图片描述


在这里插入图片描述

标签: django python 后端

本文转载自: https://blog.csdn.net/YZL40514131/article/details/128512554
版权归原作者 敲代码敲到头发茂密 所有, 如有侵权,请联系我们删除。

“【django】各种关联关系的模型类设计”的评论:

还没有评论