Django框架模型关系详解
在Django的框架中 模型时数据层,也就是管理我们的数据
在整个数据库的设计中,还有一种关系的设置,模型关系,或者叫做数据库关系
关系的讲解
一对一
简单理解就是两个表中的数据是一一对应的,例如a表中的一条数据对应着b表中的一条
例如:一个用户和用户的详情信息在数据库的设计中,应该是分开存储的。
-- 假设需要存储一个用户的很多信息,其中包括了以下字段-- ID,用户名,密码,邮箱,手机号,年龄,性别,学历,籍贯,民族,紧急联系人,头像,地址。。。。-- 1 张三。 123。@qq.com,。。 硕士 山西-- 2。李四。 567 。。 本科 山东。。。-- 像这么多的字段可以设置在一个表中进行数据的存储,但是效率不高。通常情况下会把这个数据表进行垂直分表-- 垂直分表,就是把表中的字段进行分离,分到不同的表中进行存储-- 可以像以下方式进行 垂直分表-- 用户 表 中存储 用户的主要的常用的信息数据-- id 用户名,密码,邮箱,手机号,头像,年龄,性别,-- 1 张三 。123。 @qq.com-- 2 李四。 567 。。-- 用户详情 表 中存储其它的用户信息,不常用或不重要的信息数据-- ID,学历,籍贯,民族,紧急联系人,地址。。。-- 1,本科。山东-- 2,硕士 山西-- 出现了一个问题,就是怎么证明 用户详情表中数据哪个是张三的,哪个是李四的。-- 如何解决这个问题呢?-- 给用户详情表多增加一个字段,uid,这个字段是当前行数据的用户id-- ID,UID,学历,籍贯,民族,紧急联系人,地址。。。-- 1, 2 本科。山东-- 2, 1 硕士 山西-- UID这个字段存储的是 用户表中 用户的ID主键,这样两个表就建立了关系。-- 如果用户id主键在用户详情中只能有一个,那么这种关系就是一对一关系mysql> select * from home_stu;+----+--------+-----+---------+| id | name | age | phone |+----+--------+-----+---------+| 1 | 张三 | 20 | 1231231 || 2 | 李四 | 22 | 1231231 || 3 | 王五 | 21 | 1231231 |+----+--------+-----+---------+3 rows in set (0.00 sec)mysql> select * from home_stuinfo;+----+---------+--------+--------+| id | address | xueli | sid_id |+----+---------+--------+--------+| 1 | 山东 | 本科 | 1 || 2 | 山西 | 本科 | 3 || 3 | 河南 | 本科 | 2 |+----+---------+--------+--------+
一对多
一对多关系就是一个表中的数据,对应着另外一个表中多条数据
或者反过来理解,就会多条数据同属于另外一个表的一条数据
```sql — 比如 新闻分类和新闻 — 新闻分类表 id 新闻分类名称 1 经济新闻 2 国际新闻 3 地方新闻
— 新闻表 id 新闻的标题 所属新闻分类 作者 发布时间 新闻内容 。。。 1 中国改开以来经济突飞猛进 1 2。 北京自2019年11月起限制进京证办理次数 3 3。 美国特朗普被弹劾,成为了特没谱。 2 4 2019年被称为未来最差的十年, 1
— 一对多的关系在项目非常常见: — 商品分类和商品,班级和学生,商品和商品图片
<a name="000a6247"></a>### 多对多多对多的关系就是,a表中的一条数据,对应着b表中的多条数据。同时,b表中的一条数据也对应着a表中多条数据,是双向的一对多关系。
例如: 一本书可以有多个标签 书名。 标签 <<道德经>> 古典文籍,传统文化, <<三国演义>> 历史文籍,小说 <<山海经>> 古典文集,传统文化,小说
上面这个案例中,看一本书是不是有多个标签 反过来看标签,是不是一个标签中也可以有多本书 举例:道德经这本书有两个标签,同时标签 古典文集 下是不是也有多本书呢?
书籍表 id 书名 作者 1 <<道德经>> 老子 2 <<三国演义>> 罗贯中 3 <<山海经>> 不详
标签表 id 标签名 1。 古典文籍 2。 传统文化 3。 历史文籍 4。 小说
建立第三个表,专门定义描述 多个表的关系 书籍标签关系表 id. 书籍BID 标签TID 1。 1 1 2。 1 2 3。 2 3 4。 2 4 5。 3 1 6。 3 2 7。 3 4
例如 班级和老师,一个班级有多个老师授课,一个老师到多个班级授课。
<a name="aef40cbd"></a>## 关系的实现了解了数据库中表的关系后,我们想一下,如何实现表中的关系呢?- 逻辑关系 (自己用代码逻辑实现)- 直接在需要的表中增加一个普通的字段,存储对应的另外一个表中的主键- 通过程序或者业务逻辑来控制和管理这个表关系- 物理关系(使用数据库的外键索引来实现)- 通过数据库的 外键索引 创建表的关系- 这是一种在数据库上物理形式创建的索引关系。- 不推荐使用物理外键方式建立关系:外键会导致表与表之间耦合,update与delete操作都会涉及相关联的表,十分影响sql 的性能,甚至会造成死锁。高并发情况下容易造成数据库性能下降,大数据高并发业务场景数据库使用以性能优先<a name="a62e0102"></a>## 模型关系<a name="0bc5b2d6"></a>#### 一对一关系的定义实现models.OneToOneField(Stu,on_delete=models.CASADE)django文档:[https://docs.djangoproject.com/en/2.2/topics/db/examples/one_to_one/](https://docs.djangoproject.com/en/2.2/topics/db/examples/one_to_one/)```python# 定义 学生 模型class Stu(models.Model):name = models.CharField(max_length=5)age = models.IntegerField()phone = models.CharField(max_length=11)# 定义 学生详情 模型class Stuinfo(models.Model):# 创建 一对一模型关系.sid = models.OneToOneField(Stu,on_delete=models.CASCADE)address = models.CharField(max_length=100)xueli = models.CharField(max_length=10)
一对一模型关系的使用
# 添加数据# data = {'name':'王五','age':21,'phone':'1231231','address':'河南','xueli':'本科'}# 先添加 用户数据# stuobj = models.Stu()# stuobj.name = data['name']# stuobj.age = data['age']# stuobj.phone = data['phone']# stuobj.save()# 给用户创建用户详情数据# sinfo = models.Stuinfo()# sinfo.address = data['address']# sinfo.xueli = data['xueli']# # 需要注意,在Stuinfo这个模型类中,定义了sid这个外键,因为在添加时,要指定这个外键的数据# sinfo.sid = stuobj # 注意这个外键字段要求是一个对象# sinfo.save()# 查询数据# 1.可以根据用户对象获取用户详情数据# stuobj = models.Stu.objects.get(id=2)# print(stuobj.stuinfo) # 通过用户对象 获取 用户详情对象# print(stuobj.stuinfo.address)# 2.也可以根据用户详情数据,获取用户对象# sinfo = models.Stuinfo.objects.first()# print(sinfo.address)# print(sinfo.sid.name) # 通过用户详情对象,和sid字段获取用户信息# 删除# 1. 删除用户后,对用户详情有影响吗?# 当前用户对象删除时,会随之删除相关的关联数据,对应的用户详情也会被删除stuobj = models.Stu.objects.get(id=1)stuobj.delete()# 2. 删除用户详情,对用户有影响吗?# 删除用户详情,对用户没有任何影响,因为用户详情依赖用户,但是用户不依赖用户详情
一对多模型关系的定义
models.ForeignKey(关联的模型类,on_delete=models.CASCADE)
把这个外键字段定义在多的一端,例如班级和学生,一个班级对应多个学生,因为外键定义在学生那边。
# 定义 学生 模型class Stu(models.Model):name = models.CharField(max_length=5)age = models.IntegerField()phone = models.CharField(max_length=11)# 一对多bid = models.ForeignKey('Banji',on_delete=models.CASCADE)# 定义 学生详情 模型class Stuinfo(models.Model):# 创建 一对一模型关系.sid = models.OneToOneField(Stu,on_delete=models.CASCADE)address = models.CharField(max_length=100)xueli = models.CharField(max_length=10)# 定义 班级 模型class Banji(models.Model):# 班级名称bname = models.CharField(max_length=10)'''注意 如果Stu模型类已经创建,给它添加bid外键字段时,要求进行选择默认值。方案:全部注释模型,重新创建,或者先创建班级模型,添加一些数据后在给Stu模型类定义bid并设置默认值'''
一对多模型关系的使用
# 添加数据,创建关系# 先创建班级数据bs = models.Banji.objects.all()print(bs)# 创建学生数据时需要指定对应的班级数据studata = {'name':'罗胖','age':53,'phone':'312312','bid':bs[2]}# obj = models.Stu(**studata)# obj.save()# 查询数据# 1. 可以通过班级查询学生bs = models.Banji.objects.get(id=2)print(bs.bname)# 查询这个班级对应所有的学生,print(bs.stu_set.all())# 2. 可以通过学生查询班级ss = models.Stu.objects.all()print(ss)print(ss[3].bid.bname)# 删除数据# 1. 删除班级,会影响学生吗? 会影响obj = models.Banji.objects.get(id=2)obj.delete()# 2. 删除学生,会影响班级吗?
多对多模型关系的定义
models.ManyToManyField(to,** options)
# 书籍 模型class Books(models.Model):bname = models.CharField(max_length=20)author = models.CharField(max_length=10)# 标签 模型class Tags(models.Model):tname = models.CharField(max_length=10)# 多对多模型关系定义book = models.ManyToManyField('Books')
多对多模型关系的使用
# 创建书籍# b1 = models.Books(**{'bname':'道德经','author':'老子'})# b2 = models.Books(**{'bname':'三国演义','author':'罗贯中'})# b3 = models.Books(**{'bname':'山海经','author':'不详'})# b1.save()# b2.save()# b3.save()# 创建标签# t1 = models.Tags(**{'tname':'古典文籍'})# t2 = models.Tags(**{'tname':'传统文化'})# t3 = models.Tags(**{'tname':'历史文籍'})# t4 = models.Tags(**{'tname':'小说'})# t1.save()# t2.save()# t3.save()# t4.save()# 创建关系bs = models.Books.objects.all() # 所有的 书籍对象ts = models.Tags.objects.all() # 所有的 标签对象# 可以 给书籍设置 标签# bs[0].tags_set.set([ts[0],ts[1]])# 可以 给标签设置 书籍# ts[3].book.set([bs[1],bs[2]])# 查询# 可以通过标签获取书籍# res = ts[3].book.all() # 获取标签中的所有书籍数据# 可以通过书籍获取标签# res = bs[0].tags_set.all() # 获取书籍中的所有标签数据# print(res)# 删除,删除书籍或者标签都会影响标签与书籍的关系,其它不变
