Django框架模型关系详解

在Django的框架中 模型时数据层,也就是管理我们的数据

在整个数据库的设计中,还有一种关系的设置,模型关系,或者叫做数据库关系

关系的讲解

一对一

简单理解就是两个表中的数据是一一对应的,例如a表中的一条数据对应着b表中的一条

例如:一个用户和用户的详情信息在数据库的设计中,应该是分开存储的。

  1. -- 假设需要存储一个用户的很多信息,其中包括了以下字段
  2. -- ID,用户名,密码,邮箱,手机号,年龄,性别,学历,籍贯,民族,紧急联系人,头像,地址。。。。
  3. -- 1 张三。 123@qq.com,。。 硕士 山西
  4. -- 2。李四。 567 。。 本科 山东。。。
  5. -- 像这么多的字段可以设置在一个表中进行数据的存储,但是效率不高。通常情况下会把这个数据表进行垂直分表
  6. -- 垂直分表,就是把表中的字段进行分离,分到不同的表中进行存储
  7. -- 可以像以下方式进行 垂直分表
  8. -- 用户 中存储 用户的主要的常用的信息数据
  9. -- id 用户名,密码,邮箱,手机号,头像,年龄,性别,
  10. -- 1 张三 123 @qq.com
  11. -- 2 李四。 567 。。
  12. -- 用户详情 中存储其它的用户信息,不常用或不重要的信息数据
  13. -- ID,学历,籍贯,民族,紧急联系人,地址。。。
  14. -- 1,本科。山东
  15. -- 2,硕士 山西
  16. -- 出现了一个问题,就是怎么证明 用户详情表中数据哪个是张三的,哪个是李四的。
  17. -- 如何解决这个问题呢?
  18. -- 给用户详情表多增加一个字段,uid,这个字段是当前行数据的用户id
  19. -- IDUID,学历,籍贯,民族,紧急联系人,地址。。。
  20. -- 1 2 本科。山东
  21. -- 2 1 硕士 山西
  22. -- UID这个字段存储的是 用户表中 用户的ID主键,这样两个表就建立了关系。
  23. -- 如果用户id主键在用户详情中只能有一个,那么这种关系就是一对一关系
  24. mysql> select * from home_stu;
  25. +----+--------+-----+---------+
  26. | id | name | age | phone |
  27. +----+--------+-----+---------+
  28. | 1 | 张三 | 20 | 1231231 |
  29. | 2 | 李四 | 22 | 1231231 |
  30. | 3 | 王五 | 21 | 1231231 |
  31. +----+--------+-----+---------+
  32. 3 rows in set (0.00 sec)
  33. mysql> select * from home_stuinfo;
  34. +----+---------+--------+--------+
  35. | id | address | xueli | sid_id |
  36. +----+---------+--------+--------+
  37. | 1 | 山东 | 本科 | 1 |
  38. | 2 | 山西 | 本科 | 3 |
  39. | 3 | 河南 | 本科 | 2 |
  40. +----+---------+--------+--------+

一对多

  • 一对多关系就是一个表中的数据,对应着另外一个表中多条数据

  • 或者反过来理解,就会多条数据同属于另外一个表的一条数据

  • ```sql — 比如 新闻分类和新闻 — 新闻分类表 id 新闻分类名称 1 经济新闻 2 国际新闻 3 地方新闻

— 新闻表 id 新闻的标题 所属新闻分类 作者 发布时间 新闻内容 。。。 1 中国改开以来经济突飞猛进 1 2。 北京自2019年11月起限制进京证办理次数 3 3。 美国特朗普被弹劾,成为了特没谱。 2 4 2019年被称为未来最差的十年, 1

— 一对多的关系在项目非常常见: — 商品分类和商品,班级和学生,商品和商品图片

  1. <a name="000a6247"></a>
  2. ### 多对多
  3. 多对多的关系就是,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

例如 班级和老师,一个班级有多个老师授课,一个老师到多个班级授课。

  1. <a name="aef40cbd"></a>
  2. ## 关系的实现
  3. 了解了数据库中表的关系后,我们想一下,如何实现表中的关系呢?
  4. - 逻辑关系 (自己用代码逻辑实现)
  5. - 直接在需要的表中增加一个普通的字段,存储对应的另外一个表中的主键
  6. - 通过程序或者业务逻辑来控制和管理这个表关系
  7. - 物理关系(使用数据库的外键索引来实现)
  8. - 通过数据库的 外键索引 创建表的关系
  9. - 这是一种在数据库上物理形式创建的索引关系。
  10. - 不推荐使用物理外键方式建立关系:外键会导致表与表之间耦合,update与delete操作都会涉及相关联的表,十分影响sql 的性能,甚至会造成死锁。高并发情况下容易造成数据库性能下降,大数据高并发业务场景数据库使用以性能优先
  11. <a name="a62e0102"></a>
  12. ## 模型关系
  13. <a name="0bc5b2d6"></a>
  14. #### 一对一关系的定义实现
  15. models.OneToOneField(Stu,on_delete=models.CASADE)
  16. 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/)
  17. ```python
  18. # 定义 学生 模型
  19. class Stu(models.Model):
  20. name = models.CharField(max_length=5)
  21. age = models.IntegerField()
  22. phone = models.CharField(max_length=11)
  23. # 定义 学生详情 模型
  24. class Stuinfo(models.Model):
  25. # 创建 一对一模型关系.
  26. sid = models.OneToOneField(Stu,on_delete=models.CASCADE)
  27. address = models.CharField(max_length=100)
  28. xueli = models.CharField(max_length=10)

一对一模型关系的使用

  1. # 添加数据
  2. # data = {'name':'王五','age':21,'phone':'1231231','address':'河南','xueli':'本科'}
  3. # 先添加 用户数据
  4. # stuobj = models.Stu()
  5. # stuobj.name = data['name']
  6. # stuobj.age = data['age']
  7. # stuobj.phone = data['phone']
  8. # stuobj.save()
  9. # 给用户创建用户详情数据
  10. # sinfo = models.Stuinfo()
  11. # sinfo.address = data['address']
  12. # sinfo.xueli = data['xueli']
  13. # # 需要注意,在Stuinfo这个模型类中,定义了sid这个外键,因为在添加时,要指定这个外键的数据
  14. # sinfo.sid = stuobj # 注意这个外键字段要求是一个对象
  15. # sinfo.save()
  16. # 查询数据
  17. # 1.可以根据用户对象获取用户详情数据
  18. # stuobj = models.Stu.objects.get(id=2)
  19. # print(stuobj.stuinfo) # 通过用户对象 获取 用户详情对象
  20. # print(stuobj.stuinfo.address)
  21. # 2.也可以根据用户详情数据,获取用户对象
  22. # sinfo = models.Stuinfo.objects.first()
  23. # print(sinfo.address)
  24. # print(sinfo.sid.name) # 通过用户详情对象,和sid字段获取用户信息
  25. # 删除
  26. # 1. 删除用户后,对用户详情有影响吗?
  27. # 当前用户对象删除时,会随之删除相关的关联数据,对应的用户详情也会被删除
  28. stuobj = models.Stu.objects.get(id=1)
  29. stuobj.delete()
  30. # 2. 删除用户详情,对用户有影响吗?
  31. # 删除用户详情,对用户没有任何影响,因为用户详情依赖用户,但是用户不依赖用户详情

一对多模型关系的定义

models.ForeignKey(关联的模型类,on_delete=models.CASCADE)

把这个外键字段定义在多的一端,例如班级和学生,一个班级对应多个学生,因为外键定义在学生那边。

  1. # 定义 学生 模型
  2. class Stu(models.Model):
  3. name = models.CharField(max_length=5)
  4. age = models.IntegerField()
  5. phone = models.CharField(max_length=11)
  6. # 一对多
  7. bid = models.ForeignKey('Banji',on_delete=models.CASCADE)
  8. # 定义 学生详情 模型
  9. class Stuinfo(models.Model):
  10. # 创建 一对一模型关系.
  11. sid = models.OneToOneField(Stu,on_delete=models.CASCADE)
  12. address = models.CharField(max_length=100)
  13. xueli = models.CharField(max_length=10)
  14. # 定义 班级 模型
  15. class Banji(models.Model):
  16. # 班级名称
  17. bname = models.CharField(max_length=10)
  18. '''
  19. 注意 如果Stu模型类已经创建,给它添加bid外键字段时,要求进行选择默认值。
  20. 方案:
  21. 全部注释模型,重新创建,
  22. 或者先创建班级模型,添加一些数据后在给Stu模型类定义bid并设置默认值
  23. '''

一对多模型关系的使用

  1. # 添加数据,创建关系
  2. # 先创建班级数据
  3. bs = models.Banji.objects.all()
  4. print(bs)
  5. # 创建学生数据时需要指定对应的班级数据
  6. studata = {
  7. 'name':'罗胖',
  8. 'age':53,
  9. 'phone':'312312',
  10. 'bid':bs[2]
  11. }
  12. # obj = models.Stu(**studata)
  13. # obj.save()
  14. # 查询数据
  15. # 1. 可以通过班级查询学生
  16. bs = models.Banji.objects.get(id=2)
  17. print(bs.bname)
  18. # 查询这个班级对应所有的学生,
  19. print(bs.stu_set.all())
  20. # 2. 可以通过学生查询班级
  21. ss = models.Stu.objects.all()
  22. print(ss)
  23. print(ss[3].bid.bname)
  24. # 删除数据
  25. # 1. 删除班级,会影响学生吗? 会影响
  26. obj = models.Banji.objects.get(id=2)
  27. obj.delete()
  28. # 2. 删除学生,会影响班级吗?

多对多模型关系的定义

models.ManyToManyField(to,** options

  1. # 书籍 模型
  2. class Books(models.Model):
  3. bname = models.CharField(max_length=20)
  4. author = models.CharField(max_length=10)
  5. # 标签 模型
  6. class Tags(models.Model):
  7. tname = models.CharField(max_length=10)
  8. # 多对多模型关系定义
  9. book = models.ManyToManyField('Books')

多对多模型关系的使用

  1. # 创建书籍
  2. # b1 = models.Books(**{'bname':'道德经','author':'老子'})
  3. # b2 = models.Books(**{'bname':'三国演义','author':'罗贯中'})
  4. # b3 = models.Books(**{'bname':'山海经','author':'不详'})
  5. # b1.save()
  6. # b2.save()
  7. # b3.save()
  8. # 创建标签
  9. # t1 = models.Tags(**{'tname':'古典文籍'})
  10. # t2 = models.Tags(**{'tname':'传统文化'})
  11. # t3 = models.Tags(**{'tname':'历史文籍'})
  12. # t4 = models.Tags(**{'tname':'小说'})
  13. # t1.save()
  14. # t2.save()
  15. # t3.save()
  16. # t4.save()
  17. # 创建关系
  18. bs = models.Books.objects.all() # 所有的 书籍对象
  19. ts = models.Tags.objects.all() # 所有的 标签对象
  20. # 可以 给书籍设置 标签
  21. # bs[0].tags_set.set([ts[0],ts[1]])
  22. # 可以 给标签设置 书籍
  23. # ts[3].book.set([bs[1],bs[2]])
  24. # 查询
  25. # 可以通过标签获取书籍
  26. # res = ts[3].book.all() # 获取标签中的所有书籍数据
  27. # 可以通过书籍获取标签
  28. # res = bs[0].tags_set.all() # 获取书籍中的所有标签数据
  29. # print(res)
  30. # 删除,删除书籍或者标签都会影响标签与书籍的关系,其它不变