1、什么是关系映射

在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见的关系映射有:

  1. 一对一映射
    1. 如:一个身份证对应一个人
  2. 一对多映射
    1. 如:一个班级可以有多个学生
  3. 多对多映射
    1. 如:一个班级可以有多个老师,一个老师可以教多个班级

      2、一对一关系映射

      2.1、一对一关系创建

      一对一是表示现实事物间存在的一对一的对应关系
      如:一个 平台用户 只有 一个 平台账户,一个家庭只有一个户主等等
      语法:OneToOneField(类名, on_delete=xxx) ```python from django.db import models

class User(models.Model): name = models.CharField(verbose_name=”用户名”, max_length=50) password = models.CharField(verbose_name=”密码”,max_length=32,null=True,blank=True)

class Account(models.Model): user = models.OneToOneField(User,on_delete=models.CASCADE,verbose_name=”用户”)

  1. # 一个平台用户 只有 一个平台账户
  2. money = models.IntegerField(verbose_name="余额",default=90000)
  1. <a name="tixE1"></a>
  2. ### 2.1.1、创建时-特殊字段选项
  3. <a name="w68Yw"></a>
  4. #### on_delete 级联删除(删除时说明)
  5. 1. models.CASCADE 级联删除。Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象
  6. 1. models.PROTECT 抛出ProtectedError 以阻止被引用对象的删除(等同于MySQL默认的RESTRICT)
  7. 1. models.SET_NULL 设置ForeignKey null; 需要指定 null=True
  8. 1. models.SET_DEFAULT 将ForeignKey设置为其默认值;必须设置ForeignKey的默认值。
  9. - on_delete = models.CASCADE #关联删除,删除关联字段后,该字段也同时删除
  10. - on_delete = models.DO_NOTHING #删除后什么也不做
  11. - on_delete =models.SET #设置成指定的值 例如:models.SET(1) 删除关联字段后,本字段设置成1
  12. - on_delete =models.SET_NULL #设置成null
  13. - on_delete =models.SET_DEFAULT #设置成默认值,前提是你这个字段得有默认值
  14. - on_delete =models.PROTECT#受保护 不允许删除
  15. <a name="YQQVL"></a>
  16. ## 2.2、创建数据(新增表记录)
  17. 模型类
  18. ```python
  19. from django.db import models
  20. class User(models.Model):
  21. name = models.CharField(verbose_name="用户名", max_length=50)
  22. password = models.CharField(verbose_name="密码",max_length=32,null=True,blank=True)
  23. class Account(models.Model):
  24. user = models.OneToOneField(User,on_delete=models.CASCADE,verbose_name="用户")
  25. # 一个平台用户 只有 一个平台账户
  26. money = models.IntegerField(verbose_name="余额",default=90000)
  • 先创建身上没有定义关系的表记录
  • 再创建身上定义关系的表记录

无外键的模型类 User :

创建方式:(先创建身上没有定义关系的表记
user1 = User.objects.creat(name=”小新同学”)

有外键的模型类 Account:

(再创建身上定义关系的表记录)
创建方式1:
a1 = models.Account.objects.create(money=10000,user=user1) # 关联 小新同学的 object 管理器对象
创建方式2:
a1 = models.Account.objects.create(money=10000,user_id=user1.id) #关联 小新同学对应的主键值
a1 = models.Account.objects.create(money=10000,user_id=1) #关联 小新同学对应的主键值

2.3、查询数据(查询表记录)

正向查询:

直接通过外键属性查询,则称为正向查询

  1. from user import models
  2. a1 = models.Account.objects.get(id=1)
  3. print("账户id是1的用户是",a1.user.name)

image.png

反向查询:

没有外键属性的一方,可以调用反向属性查询到关联的另一方
反向关联属性为 实例对象.引用类名(小写)

  1. from user import models
  2. user1 = models.User.objects.get(name="特朗普")
  3. print(user1.name,"的账户余额是:",user1.account.money)
  4. # 直接通过account外键属性查询,则称为正向查询

image.png

3、一对多关系映射

一对多是表现现实事物间存在一对多的对应关系
如:一个文章分类有多篇文章,
一对多需要明确出具体角色,在多表上设置外键

3.1、一对多关系创建

语法:
当一个A类对象(文章分类)可以关联多个B类对象(文章)时
ForeignKey必须指定 on_delete模式

related_name参数:自定义一个名称,用于反向查询
当一张子表里,多个foreignkey指向同一个主表,related_name必须设置。

  1. class A(model.Model):
  2. ...
  3. class B(model.Model):
  4. 属性 = models.ForeignKey("一"的模型类 , on_delete=xxx)

示例:

  1. from django.db import models
  2. class Category(models.Model):
  3. name = models.CharField(max_length=50, unique=True, verbose_name="分类名称")
  4. class Article(models.Model):
  5. title = models.CharField(max_length=80, verbose_name="文章名称")
  6. content = models.TextField(verbose_name="文章内容")
  7. category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, verbose_name="归属分类")
  8. # ForeignKey定义外键,创建1对多关系

3.2、创建数据

  • 先创建“一”
  • 再创建“多” ```python from user import models

c1 = models.Category.objects.create(name=”Python文章分类”)

models.Article.objects.create(title=”文章1”,category=c1)

通过关联对象创建

models.Article.objects.create(title=”文章2”,category_id=c1.id) models.Article.objects.create(title=”文章2”,category_id=1)

通过关联对象对应的主键创建

  1. <a name="Hboyf"></a>
  2. ## 3.3、查询数据
  3. <a name="qnWCL"></a>
  4. ### 正向查询:
  5. 通过 category **属性**查询即可
  6. ```python
  7. a1 = models.Article.objects.get(title="文章1")
  8. print(a1.title,"的所属文章分类是",a1.category.name)

反向查询:

通过 Category(文章分类) 查询对应的所有 Article(文章)
需要用到反向属性

  1. c1 = models.Category.objects.get(name="Python文章分类")
  2. articles = c1.article_set.all()
  3. # 通过article_set 获取c1 对应的多个 Article数据对象
  4. # articles = models.Article.objects.filter(category=c1)
  5. # 也可以采用这种方式获取
  6. print("Python文章分类,下的文章有:")
  7. for a in articles:
  8. print(a.title)

4、多对多关系映射

定义:
多对多表达对象之间多对多的复杂关系;
如:每个班级都有不同的老师(张老师、李老师、王老师),每个老师都有不同的班级(1班,2班,3班)

MySQL、SQLit 等数据库中创建多对多,需要依赖第三张表来实现
Django中无需手动创建第三张表,Django自动完成

4.1、多对多关系创建

语法:
在关联的两个类中的任意一个类中,增加
属性 = models.ManyToManyField(MyModel)

示例:
一个班级可以有多个老师
一个老师可以有多个班级

  1. from django.db import models
  2. class Grade(models.Model):
  3. name = models.CharField(verbose_name="班级名称", max_length=50)
  4. class Teacher(models.Model):
  5. name = models.CharField(verbose_name="老师名称", max_length=50)
  6. grade = models.ManyToManyField(Grade,verbose_name="班级")

4.2、创建数据

方案1:先创建 班级 grade 再关联 teacher

  1. grade1 = models.Grade.objects.create(name="1班")
  2. grade2 = models.Grade.objects.create(name="2班")
  3. teacher1 = grade1.teacher_set.create(name="张老师")
  4. grade2.teacher_set.add(teacher1)
  5. # 张老师 是1班的老师 也是2班的老师

方案2:先创建 teacher 再关联 grade

  1. teacher2 = models.Teacher.objects.create(name="李老师")
  2. grade3 = teacher2.grade.create(name="2班")
  3. teacher2.grade.add(grade1)
  4. # 李老师 是2班的老师,也是1班的老师

4.3、查询数据

正向查询:

正向查询 有多对多属性的对象 查 另一方
通过 Teacher 查询对应的 所有 Grade
此时多对多属性 等价于 object

  1. teacher2.grade.all() # 获取 teacher2 对应的所有 grade 班级的信息
  2. teacher2.grade.filter(name="1班")
  3. # 获取teacher2 李老师 对应的 名字叫做 1班的 班级信息

反向查询

通过 Grade 查询对应的 所有 Teacher
利用反向属性 teacher_set

  1. grade1.teacher_set.all()
  2. grade1.teacher_set.filter()

多对多小练习

待补充

参考博客

知乎:Django进阶笔记(1)——ForeignKey的爱恨情仇
https://zhuanlan.zhihu.com/p/25393972
CSDN:Django如何创建指向同一个模型的多个外键?
https://blog.csdn.net/laiqun_ai/article/details/45740543