Django基础入门⑪:DjangoDjango数据表关联
- Django数据表关联
- 一对一关系类型
- 语法格式
- 实例应用
- 一对多关系类型
- 必填参数
- 可选参数
- 语法格式
- 实例应用
- 多对多关系
- ManyToManyFiled定义
- 可选参数
- 语法格式
- 多对多中间表
- 实例应用
🏘️🏘️个人简介:以山河作礼。
🎖️🎖️:Python领域新星创作者,CSDN实力新星认证,阿里云社区专家博主,CSDN内容合伙人
🎁🎁:Web全栈开发专栏:《Web全栈开发》免费专栏,欢迎阅读!
🎁🎁:文章末尾扫描二维码可以加入粉丝交流群,不定期免费送书。
Django数据表关联
Django数据表关联通过ORM(对象关系映射)技术实现不同模型(Model)之间的关联,建立表与表之间的关系。
在Django中,有以下三种常见的数据表关联方式:
一对一关联(One-to-One)
:关系中的每个对象都与另一个对象有且只有一个关联,例如一个人只有一个身份证号码。一对多关联(One-to-Many)
:关系中的一个对象对应另一个对象的多个实例,例如一个班级有多个学生。多对多关联(Many-to-Many
:关系中的每个对象都可以与多个其他对象相关联,例如一个学生可以选择多个课程,一个课程也可以有多个学生选择。
Django提供了各种类型的字段来处理这些关联,例如外键
ForeignKey(一对多)
、OneToOneField(一对一字段
)和ManyToManyField(多对多字段)
等。通过这些字段,我们可以轻松地创建表与表之间的关联,接下来我们来简单了解下。
一对一关系类型
OneToOneFiled
继承自ForeignKey
,在概念上,它类似unique=Ture
的ForeignKey
,它与ForeignKey
最显著的区别在于反向查询上,ForeignKey
反向查询返回的是一个对象实例列表,而OneToOneFiled
反向查询返回的是一个对象实例。- 一对一关系类型的使用和场景相对其他两种关联关系要少,经常用于对已有 Model 的扩展,例如我们可以对 UserInfo表进行扩展,添加类似用户昵称、个性签名等字段。此时就可以新建一个 Model,并定义一个字段与 UserInfo表一对一关联。这样就实现了用户信息拓展表与 UserInfo 表一对一关联,下面会用通过实例进行说明。
语法格式
class A(model.Model): ...
# 和A表进行1对1
class B(model.Model):attr = models.OneToOneField(A)
实例应用
新建 index\models.py 下添加以下代码:
#新建一对一关用户信息表拓展表,添加完成后执行数据库迁移同步操作
class ExtendUserinfo(models.Model):user=models.OneToOneField(to=UserInfo,on_delete=models.CASCADE)signature=models.CharField(max_length=255,verbose_name='用户签名',help_text='自建签名')nickname=models.CharField(max_length=255,verbose_name='昵称',help_text='自建昵称')
Django添加数据,添加数据的user对象必须是另外一个表的类型,如下所示:
from index.models import UserInfo,ExtendUserinfo
username=UserInfo.objects.create(username="xiaoming",password="******")# 创建一对一表关联
ExtendUserinfo.objects.create(user=username,signature="good",nickname="XH")
一对多关系类型
一对多是常用的关系类型,这种类型在数据库中体现是外键关联关系,它在和其他的 Model 建立关联同时也和自己建立关联,用来描述一对多的关系,例如一个作者可以写很多不同的书,但是这些书又只能对应这一个作者,再比如一本图书只能属于一个出版社,一个出版社可以出版很多不同种类的图书,这就是一对多的关系。
Django 会自动将字段的名称添加“_id”作为列名,ForgienKey 的定义如下:
model.ForeignKey(to,on_delete,**options)
必填参数
它有两个必填参数。to,指定所关联的 Model,它的中取值可以是直接引用其他的 Model,也可以是 Model 所对应的字符串名称;on_delete,当删除关联表的数据时,Django 将根据这个参数设定的值确定应该执行什么样的 SQL 约束。
on_delete 可以理解为 MySQL 外键的级联动作,当主表执行删除操作时对子表的影响,即子表要执行的操作,Django 提供的可选值如下所示:
CASCADE
,级联删除,它是大部分 ForeignKey 的定义时选择的约束。它的表现是删除了“主”,则“子”也会被自动删除。PROTECT
,删除被引用对象时,将会抛出 ProtectedError 异常。当主表被一个或多个子表关联时,主表被删除则会抛出异常。SET_NULL
,设置删除对象所关联的外键字段为 null,但前提是设置了选项 null 为True,否则会抛出异常。
+SET_DEFAULT
:将外键字段设置为默认值,但前提是设置了 default 选项,且指向的对象是存在的。SET(value)
:删除被引用对象时,设置外键字段为 value。value 如果是一个可调用对象,那么就会被设置为调用后的结果。DO_NOTHING
:不做任何处理。但是,由于数据表之间存在引用关系,删除关联数据,会造成数据库抛出异常。
可选参数
除了必填参数以外,ForeignKey 还有一些常用的可选参数需要关注。如下所示:
-
to_field
:关联对象的字段名称。默认情况下,Django 使用关联对象的主键(大部分情况下是 id),如果需要修改成其他字段,可以设置这个参数。但是,需要注意,能够关联的字段必须有 unique=True 的约束。 -
db_constraint
:默认值是 True,它会在数据库中创建外键约束,维护数据完整性。通常情况下,这符合大部分场景的需求。如果数据库中存在一些历史遗留的无效数据,则可以将其设置为 False,这时就需要自己去维护关联关系的正确性了。
语法格式
#一个A类实例对象关联多个B类实例对象
class A(model.Model):
....
class B(model.Model):属性 = models.ForeignKey(多对一中"一"的模型类, ...)
实例应用
修改原来定义的代码,将出版社与图书之间修改为一对多的关系,添加如下代码:
from django.db import models
#新建出版社表
class PubName(models.Model):pubname=models.CharField('名称', max_length=255, unique=True)# 创建book表
class Book(models.Model):title = models.CharField(max_length=30, unique=True, verbose_name='书名')# public = models.CharField(max_length=50, verbose_name='出版社')price = models.DecimalField(max_digits=7, decimal_places=2, verbose_name='定价')retail_price = models.DecimalField(max_digits=7, decimal_places=2, verbose_name='零售价', default="30")# 设置外键pub = models.ForeignKey(to=PubName, on_delete=models.CASCADE, null=True) # 创建Foreign外键关联pub,以pub_id关联def __str__(self):return "title:%s pub:%s price:%s" % (self.title, self.pub, self.price)
此处需要注意每次更改完 models 都需要进行数据库迁移操作,依次执行以下命令即可:
python manage.py makemigrations
python manage.py migrate
如果迁移失败,需要删除数据中的所有表,再重新迁移。
插入数据创建一对多对象,如下所示:
from index.model import *
#创建PubName实例化对象pub1并插入书籍信息
pub1=PubName.objects.create(pubname="清华出版社")
Book.objects.create(title="Python",price="59.00",retail_price="59.00",pub=pub1)
Book.objects.create(title="Redis",price="25.00",retail_price="25.00",pub=pub1)
Book.objects.create(title="Java",price="45.00",retail_price="45.00",pub=pub1)
#创建PubName实例化对象pub2并插入书籍信息
pub2=PubName.objects.create(pubname="北大出版社")
Book.objects.create(title="Django",price="65.00",retail_price="65.00",pub=pub2)
Book.objects.create(title="Flask",price="45.00",retail_price="45.00",pub=pub2)
Book.objects.create(title="Tornado",price="35.00",retail_price="35.00",pub=pub2)
访问 MySQL 数据库分别查询 index_book、index_pubname 数据表(如下所示):
多对多关系
- 多对多关系也是比较常见的,比如一个作者可以写很多本书,一本书也可以由很多作者一起完成,那么这时候 Author 和 Book之间就是多对多的关系。
- Django 通过中间表的方式来实现 Model 之间的多对多的关系,这和 MySQL中实现方式是一致的。这个中间表我们可以自己提供,也可以使用 Django 默认生成的中间表。
ManyToManyFiled定义
ManyToManyFiled(to,**options)
它只有一个必填的参数即 to,与其他两个关联词在一样,用来指定与当前的 Model 关联的 Model。
可选参数
当然 ManyToManyFiled 还有一些重要的可选参数,下面我们对它们依次进行介绍:
relate_name
与ForeignKey
中的相同都用于反向查询。db_table
用于指定中间表的名称,如果没有提供,Django 会使用多对多字段的名称和包含这张表的 Model 的名称组合起来构成中间表的名称,当然也会包含 index 前缀。through
用于指定中间表,这个参数不需要设置,Django会自动生成隐式的through Model
。由于 Django可以生成自身默认的中间表,该参数可以让用户自己去控制表之间的关联关系或者增加一些额外的信息。
语法格式
class Author(models.Model):...
class Book(models.Model):...authors = models.ManyToManyField(Author)
多对多中间表
创建 Author 与 Book 之间多对多关联关系,在 Author Model 中添加如下代码:
books=models.ManyToManyField(to="Book") #创建多对多映射关系
然后再执行数据库迁移命令,刷新数据库,可以看到如下中间表:
实例应用
插入作者信息数据,如下所示:
author1=Author.objects.create(name="Luncy",email="123456@qq.com")
author2=Author.objects.create(name="Tom",email="456789@163.com")
因为书籍信息之前已经准备完毕,所以下面我们开始创建多对多映射关系,我们在 Django shell 进行如下操作:
author1.books.add(Book.objects.get(id="1"))
author1.books.add(Book.objects.get(id="2"))
author1.books.add(Book.objects.get(id="3"))
author2.books.add(Book.objects.get(id="1"))
author2.books.add(Book.objects.get(id="4"))
author2.books.add(Book.objects.get(id="5"))
author2.books.add(Book.objects.get(id="3"))
author2.books.add(Book.objects.get(id="6"))
author1.books.add(Book.objects.get(id="6"))
- 多对多关系在中间表插入数据需要使用 add() 方法,books 是对应的多对多字段。
通过以上代码就完成多对多关系的创建,最后在 MySQL 中查看多对多相关联的三张数据表,如下所示:
书籍信息表:
作家信息表:
中间表: