8. 数据库表的关联 您所在的位置:网站首页 关联数据是什么 8. 数据库表的关联

8. 数据库表的关联

2023-08-25 03:05| 来源: 网络整理| 查看: 265

操作系统: windows IDE: Pycharm

后端系统开发中, 数据库设计是重中之重。特别是前后端分离的系统, 后端的职责基本就是数据管理, 开发的代码几乎都是围绕数据操作的。

因此,常用的数据库表和表之间的关系的设计就很重要。 目前使用的数据库系统主要还是关系型数据库(建立在关系模型基础上的数据库) 。

常见的关系型数据库:mysql、oracle、 sqlserver、SQLite ;常见的非关系型数据库:mongodb;

而关系型数据库,设计的一个难点就是各种表之间的关联关系 。 常见的3种关联关系就是: 一对多 , 一对一 , 多对多

一对多:

表之间一对多的关系,就是外键关联关系

现在系统中, 已经定义了客户(Customer)这张表 :

class Customer(models.Model): # 客户名称 name = models.CharField(max_length=200) # 联系电话 phonenumber = models.CharField(max_length=200) # 地址 address = models.CharField(max_length=200)

还需要定义药品(Medicine)这张表,包括药品名称、编号和描述 这些信息。 添加如下的类定义:

class Medicine(models.Model): # 药品名 name = models.CharField(max_length=200) # 药品编号 sn = models.CharField(max_length=200) # 描述 desc = models.CharField(max_length=200)

接下来我们还要定义 订单(Order)这张表,这个Order表包括创建日期、客户、药品、数量。

其中: 客户字段对应的客户 只能是 Customer 中的某个客户记录,也就是说Order表里面的一条订单记录的客户对应 Customer表里面的一条客户记录。

而且一个客户记录可以对应多条订单记录。

这就是一对多的关系: 在这里插入图片描述 像这种一对多的关系,数据库中是用外键来表示的。

如果一个表中的某个字段是外键,那就意味着这个外键字段的记录的取值,只能是它关联表的某个记录的主键的值。

我们定义表的 Model类的时候,如果没有指定主键字段,migrate 的时候 Django 会为该Model对应的数据库表自动生成一个id字段,作为主键。

比如,我们这里,Customer、Medicine表均没有主键,但是在migrate之后,查看数据库记录就可以发现有一个id字段,且该字段是主键 (primary key)。

Django中用models.ForeignKey()方法实现一对一的关系,如下:

common/models.py:

from django.db import models import datetime # Create your models here. #存放数据库表对象 class Customer(models.Model): #客户名称 name = models.CharField(max_length=200) #对应数据库中的varchar #联系电话 phonenumber = models.CharField(max_length=200) #地址 address = models.CharField(max_length=200) class Medicine(models.Model): # 药品名 name = models.CharField(max_length=200) # 药品编号 sn = models.CharField(max_length=200) # 描述 desc = models.CharField(max_length=200) class Order(models.Model): # 订单名 name = models.CharField(max_length=200, null=True, blank=True) # 创建日期 create_date = models.DateTimeField(default=datetime.datetime.now) # 客户 customer字段是外键, 和Customer类的主键关联 customer = models.ForeignKey(Customer, on_delete=models.PROTECT)

补充: on_delete 参数指定了当我们删除外键指向的主键记录时, 系统的行为。 on_delete 不同取值对应不同的做法,常见的做法如下:

CASCADE:删除主键记录和相应的外键表记录

比如,我们要删除客户张三,在删除了客户表中张三记录同时,也删除Order表中所有这个张三的订单记录。

PROTECT:禁止删除记录

比如,我们要删除客户张三,如果Order表中还有张三的订单记录,Django系统就会抛出ProtectedError类型的异常,当然也就禁止删除客户记录和相关的订单记录了。 除非我们将Order表中所有张三的订单记录都先删除掉,才能删除该客户表中的张三记录。

SET_NULL:删除主键记录,并且将外键记录中外键字段的值置为null

前提是外键字段要设置为值允许是null。

比如,我们要删除客户张三时,在删除了客户张三记录同时,会将Order表里面所有的 张三记录里面的customer字段值置为 null。 但是上面我们并没有设置 customer 字段有 null=True 的参数设置,所以,是不能取值为 SET_NULL的。

定义完之后,还是老方法,在根目录cmd执行:

python manage.py makemigrations commonpython manage.py migrate 在这里插入图片描述 数据库中就多了两个表,

注意:

定义的时候如果没有声明主键,Django会自动多一个id字段作为主键可以看到common_order表中的customer_id字段,比定义的时候多了一个_id,因为这是作为外键和common_customer表的主键id关联了 一对一:

外键是一对多的关系,有的时候,表之间是一对一的关系。

比如,某个学校的学生表和学生的地址表,就形成一对一的关系,即一条主键所在表的记录只能对应一条外键所在表的记录。

Django中用OneToOneField()方法实现一对一的关系,如下:

class Student(models.Model): # 姓名 name = models.CharField(max_length=200) # 班级 classname = models.CharField(max_length=200) # 描述 desc = models.CharField(max_length=200) class ContactAddress(models.Model): # 一对一 对应学生表 student = models.OneToOneField(Student, on_delete=models.PROTECT) # 家庭 homeaddress = models.CharField(max_length=200) # 电话号码 phone = models.CharField(max_length=200)

Django发现这样一对一定定义,它会在migrate的时候,在数据库中定义该字段为外键的同时, 加上unique=True约束(在底层数据库实现),表示在此表中,所有记录的该字段取值必须唯一,不能重复。

多对多:

数据库表还有一种多对多的关系。

在当前系统中, 一个订单可以采购多种药品,就对应Medicine表里面的多种药品; 而一种药品也可以被多个订单采购, 那么Order表和Medicine表 之间就形成了多对多的关系。

Django是通过 ManyToManyField 对象 表示 多对多的关系。 修改models.py中的Order类:

class Order(models.Model): # 订单名 name = models.CharField(max_length=200, null=True, blank=True) # 创建日期 create_date = models.DateTimeField(default=datetime.datetime.now) # 客户 customer = models.ForeignKey(Customer, on_delete=models.PROTECT) # 订单购买的药品,和Medicine表是多对多的关系 medicines = models.ManyToManyField(Medicine, through='OrderMedicine') class OrderMedicine(models.Model): order = models.ForeignKey(Order, on_delete=models.PROTECT) medicine = models.ForeignKey(Medicine, on_delete=models.PROTECT) # 订单中药品的数量 amount = models.PositiveIntegerField()

像这样:

medicines = models.ManyToManyField(Medicine, through='OrderMedicine')

指定Order表和 Medicine 表的多对多关系, 其实Order表中并不会产生一个叫 medicines 的字段。

Order表和 Medicine 表的多对多关系是通过另外一张表, 也就是through参数 指定的 OrderMedicine表来确定的,

migrate的时候,Django会自动产生一张新表 (这里就是 common_ordermedicine)来 实现 order 表 和 medicine 表之间的多对多的关系。

同样的,在根目录cmd执行:

python manage.py makemigrations commonpython manage.py migrate

可以看到数据库中多了一张common_ordermedicine表,用来实现订单表和药品表的多对多关系。

外键medicine_id关联了common_medicine表,外键order_id关联了common_order表。 在这里插入图片描述 比如一个order表的订单id 为 1, 如果该订单中对应的药品有3种,它们的id分别 为 3,4,5。 那么就会有类似这样的这样3条记录在 common_order_medicine 表中。

order_idmedicine_id131415

因为要多一个字段,例如药品的数量,所以要用through='OrderMedicine',也就是说如果不需要额外字段的话,through可以省略



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有