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

news2024/12/27 14:10:19

在这里插入图片描述


文章目录

  • 前言
  • 一、级联操作
  • 二、一对多(多对一)的关联模型类设计
    • 1、学生表模型类设计
    • 2、渠道表模型类设计
  • 三、多对多的关联模型类设计
    • 1、课程表模型类设计
  • 四、多对多的关联模型类设计(自定义中间表)
    • 1、模型类设计
      • 课程表模型类设计
      • 报名表模型类设计
    • 2、数据表字段
    • 3、数据表结构
  • 五、一对一的关联模型类设计
    • 1、模型类设计
    • 2、数据表结构
    • 3、数据表字段

前言

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

一、级联操作

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一般是成对出现的

class Student(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='外键字段')  #不允许删除

    class Meta:
        db_table="t_student"        #指定生成数据库表的名称,如果不定义则自动生成crm_student
        verbose_name='学生表'
        verbose_name_plural=verbose_name    #在django-admin中模型的名字
        ordering=['id']     #排序

    def __str__(self):
        return self.name

2、渠道表模型类设计

class Channel(models.Model):
    name=models.CharField(help_text='渠道名称',
                          verbose_name='渠道名称',
                          unique=True,
                          max_length=128)

    class Meta:
        db_table='t_channel'
        verbose_name='渠道表'
        verbose_name_plural=verbose_name

    def __str__(self):
        return self.name


class Course(models.Model):
    name=models.CharField(help_text='课程名称',
                          verbose_name='课程名称',
                          unique=True,
                          max_length=128)
    students=models.ManyToManyField('Student',
                               help_text='报名学生',
                               verbose_name='报名学生')

    class Meta:
        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、课程表模型类设计

class Course(models.Model):
    name=models.CharField(help_text='课程名称',
                          verbose_name='课程名称',
                          unique=True,
                          max_length=128)
    students=models.ManyToManyField('Student',
                               help_text='报名学生',
                               verbose_name='报名学生')

    class Meta:
        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、模型类设计

课程表模型类设计

class Course(models.Model):
    name = models.CharField(help_text='课程名称',
                            verbose_name='课程名称',
                            unique=True,
                            max_length=128)
    students = models.ManyToManyField('Student',
                                      help_text='报名学生',
                                      verbose_name='报名学生',
                                      through='Entry')


    class Meta:
        db_table = 't_course'
        verbose_name = '课程表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

报名表模型类设计

class Entry(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)

    class Meta:
        db_table = 't_entry'
        verbose_name = '报名表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return f'{self.student.name}报名了{self.course.name}课程'

2、数据表字段

在这里插入图片描述

3、数据表结构

数据库迁移后django不会自动创建这两个外键的联合唯一索引

在这里插入图片描述
如果有需要,需要手动创建,在Meta类中添加如下代码

constraints=[UniqueConstraint(fields('student','course'),name='student_course_unique') ]

class Entry(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)

    class Meta:
        db_table = 't_entry'
        verbose_name = '报名表'
        verbose_name_plural = verbose_name
        #todo 多字段联合唯一索引
        constraints=[
            UniqueConstraint(fields=('student','course'),name='student_course_unique')
        ]

    def __str__(self):
        return f'{self.student.name}报名了{self.course.name}课程'

数据表结构

在这里插入图片描述

五、一对一的关联模型类设计

在django中要表达多对多的关系需要用到OneToOneField字段

学生表和学生详情表的关系为一对一的关系,创建学习详情模型表如下

1、模型类设计

class StudentDetail(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以上')

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

在这里插入图片描述


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

神经网络的学习率如何选择?

文章目录学习率的概念学习率的选择方法参考资料学习率的概念 这里的学习率指的是深度学习神经网络训练过程中选取的一个超参数。 学习率作为参数更新时的一个乘数项,可以影响网络训练的速度,或者说是每次迈步的大小。 可以这样理解,如果学…

ZC706P+ADRV9009连接RADIOVERSE详解之二

上一个BLOG我们在WIN上安装了RADIOVERSE软件以及做好了SD卡映像。这篇文字我们记录ZC706ADRV9009硬件链接情况: 这里看到USB UART串口是可选的,主要是用来查看启动的系统log。 实际连接如下: 图中: 1,外接12V电源 2…

Python数据结构与算法篇(三)-- 队列的实现和应用

1 队列 1.1 简单队列 队列是一种有次序的数据集合,其特征是新数据项的添加总发生在一端(通常称为“尾rear”端);而现存数据项的移除总发生在另一端(通常称为“首front”端)。当一个元素被加入到队列之后&a…

头歌作业之排序1、2、3、4

(PS:直接拿的友友zy的) 一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055qq.com Time of completion:2023.1.1 Last edited: 2023.1.1 目录 (PS:直接拿的友友的&a…

SCI论文解读复现【NO.2】基于注意机制的YOLOv5改进算法在行星图像中的应用(代码已复现)

此前出了目标检测算法改进专栏,但是对于应用于什么场景,需要什么改进方法对应与自己的应用场景有效果,并且多少改进点能发什么水平的文章,为解决大家的困惑,此系列文章旨在给大家解读发表高水平学术期刊中的SCI论文&am…

EMNLP22提示模板生成:GPS: Genetic Prompt Search for Efficient Few-shot Learning

GPS: Genetic Prompt Search for Efficient Few-shot Learning 1 简介 Genetic Prompt Search (GPS) 通过提示改进少样本学习,它利用遗传算法自动搜索高性能提示 遗传提示搜索 (GPS) 算法,该算法使用生成模型逐渐改变提示,并根据它们在小型…

C语言网刷题记录

作者:会敲代码的Steve 座右铭:博学笃志,切问静思。 大家好久不见啊,一看时间我已经好久没发文章了,最近在刷OJ题和学习;就没那么多心思把时间花在写文章上了,我对此感到很抱歉,本文呢…

int8,FLOPS,FLOPs,TOPS 等具体含义

1、定义 算力的计量单位FLOPS(Floating-point operations per second),FLOPS表示每秒浮点的运算次数。具体使用时,FLOPS前面还会有一个字母常量,例如TFLOPS、PFLOPS。这个字母T、P代表次数,T代表每秒一万亿…

Linux学习笔记——MySQL数据库管理系统安装部署

5.1、MySQL数据库管理系统安装部署 5.1.1、简介 1、MySQL简介 MySQL数据库管理系统(后续简称MySQL),是一款知名的数据库系统,其特点是:轻量、简单、功能丰富。 MySQL数据库可谓是软件行业的明星产品,无…

xilinx ZYNQ 7000 AXI GPIO

.0AXI GPIO 第一部分 PS 和 PL之间的通讯有一个接口称为AXI。AXI总线具体的内容这边不去深究,可以理解为一种特殊协议的通讯方式。 AXI GPIO是什么意思? PL是FPGA它可以做成任何你想要的东西,做一个GPIO外设当然是可以的。 如上图所示&…

DoIP协议从入门到精通——通信建立

在DoIP专栏中,关于DoIP文章,主要讲述从车辆物理连接、车辆声明、车辆通信激活(Routine Activation)和诊断通信几个步骤。 本文介绍了Tester与车辆获取物理连接、车辆声明自身信息后接下来需要操作的就是本文所要分享的内容:Tester与车辆控制器的通信建立。 一、通信模式…

记一次堆外内存泄漏分析

文章目录1. 背景2. JVM 内存分布与分析2.1 JVM 内存分布2.2 堆外内存泄漏分析思路2.3 服务器 JVM 参数配置及实际内存分布2.4 JVM native 内存查看2.5 手动触发 Full GC3. 问题排查经历3.1 定位内存泄漏的位置及初步猜想1)定位 RES 区域存在内存泄漏2)分…

寒假每日一题W1D1——孤独的照片

题目描述 Farmer John 最近购入了 N 头新的奶牛,每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一。 奶牛目前排成一排,Farmer John 想要为每个连续不少于三头奶牛的序列拍摄一张照片。 然而&…

一本通 1267:【例9.11】01背包问题(详细代码)

经典01背包问题 这里给你3种方法 目录 DFS 思路: 代码: DFS记忆化 思路: 代码: 动态规划 思路: 代码: DFS 时间复杂度 :O(2^n) 思路: DFS求出所有选法,再用…

Maven 之 依赖管理

目录 1、依赖传递 小案例: 2、可选依赖 3、 排除依赖 4、可选依赖和排除依赖的区别 我们开发一个工程需要用到大量得jar包,而这些jar 包就是我们所说得依赖,一个项目可以配置多个依赖。 1、依赖传递 我们来看一下今天用来演示的工程。…

Linux性能学习(1.4):CPU_如何查看CPU上下文切换参数

文章目录1 系统总体上下文参数2 进程的上下文切换参数3 其它参考资料:vmstat:一个标准的报告虚拟内存统计工具 在前面大致了解了上下文切换的相关知识,那么如何在系统中查看上下文切换相关的参数? 1 系统总体上下文参数 使用vm…

人工势场法路径规划算法(APF)

本文主要对人工势场法路径规划算法进行介绍,主要涉及人工势场法的简介、引力和斥力模型及其推导过程、人工势场法的缺陷及改进思路、人工势场法的Python与MATLAB开源源码等方面 一、人工势场法简介 人工势场法是由Khatib于1985年在论文《Real-Time Obstacle Avoidan…

WPF使用触发器需要注意优先级问题

总目录 文章目录总目录前言一、问题开始二、问题说明三、问题订正总结前言 WPF使用触发器需要注意优先级问题 一、问题开始 现在有个需求: 初始状态(未选中)的时候,CheckBox的Content 为 “乒乓球”,然后选中之后&am…

python机器学习《基于逻辑回归的预测分类》

前言: 本文所有代码均在阿里天池实验室运行,本机的jupyter notebook也可运行。除此之外,还需要导入numpy,matplotlib,sklearn,seaborn包。每期文章前面都会有环境搭建说明。文中的讲解知识点均是按照从上往下讲解,将一些平常未接触…

⼯⼚⽅法模式

⼯⼚⽅法模式 ⼯⼚⽅法模式,属于创建者模式中的一种,这类模式提供创建对象的机制, 能够提升已有代码的灵活性和可复⽤性。 创建者模式包括:⼯⼚⽅法、抽象⼯⼚、⽣成器、原型、单例,这5类。 1.⼯⼚⽅法模式介绍 ⼯⼚…