博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django 数据库基础
阅读量:243 次
发布时间:2019-03-01

本文共 4137 字,大约阅读时间需要 13 分钟。

后端系统开发中, 数据库设计是重中之重。

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

虽然,我们教程不是专门讲数据库的, 但也必须讲解常用的 数据库表 和 表之间的关系 的设计 。

目前 使用的数据库系统 主要还是 关系型数据库 。

什么是关系型数据库?就是建立在关系模型基础上的数据库。

大家耳熟能详的mysql、oracle、 sqlserver、SQLite 都是,而 mongodb、Cassandra不是

 

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

常见的3种关联关系就是: 一对多 , 一对一 , 多对多

 

一对多

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

比如,我们的 BYSMS 系统中, 已经定义了 客户(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表里面的一条客户记录

而 多条 Order记录里面的客户 是可以对应 Customer 表里面 同一个客户记录的,

反过来说,就是:一个客户记录可以对应多条订单记录

这就是一对多的关系,可以用如下图片表示

像这种一对多的关系,数据库中是用 外键 来表示的。

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

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

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

 

import datetimeclass 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)

大家可以发现, customer 字段 是外键, 指向 Customer 类。 意思就是告诉Django: Order表的 customer 字段 指向 Customer表的主键 的一个外键。

另外一个参数 on_delete 指定了 当我们想 删除 外键指向的主键 记录时, 系统的行为。

比如 我们要删除客户记录, 那么 Order表中 对应这个客户的订单记录 该如何处理呢?

on_delete 不同取值对应不同的做法,常见的做法如下

  • CASCADE

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

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

  • PROTECT

    禁止删除记录。

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

    除非我们将Order表中所有张三的订单记录都先删除掉,才能删除该客户表中的张三记录。

  • SET_NULL

    删除主键记录,并且将外键记录中外键字段的值置为null。 当然前提是外键字段要设置为值允许是null。

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

 

外键是 一对多 的关系, 也可以说是 多对一 的关系。

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

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

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 约束,表示在此表中,所有记录的该字段 取值必须唯一,不能重复。

 

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

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

其对应关系可以用下图来表示

import datetimeclass 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 表之间的多对多的关系。

大家可以执行下面两行命令 migrate 试一下

python manage.py makemigrations commonpython manage.py migrate

 

可以发现这张表中有 order_id 和 medicine_id 两个字段。

比如一个order表的订单id 为 1, 如果该订单中对应的药品有3种,它们的id分别 为 3,4,5。 那么就会有类似这样的这样3条记录在 common_order_medicine 表中。

order_id medicine_id
1 3
1 4
1 5

 

转载地址:http://iamv.baihongyu.com/

你可能感兴趣的文章