一、什么是关系映射
在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见关系映射有:
-
一对一映射
如:一个身份证对应一个人
-
一对多映射
如:一个班级可以有多个学生
-
多对多映射
如:一个学生可以报多个课程,一个课程可以有多个学生学习
二、一对一关系
一对一是表示现实事务见存在的一对一的对应关系
如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
语法:
OneToOneFieId(类名, on_delete=xxx)
示例:
class A(models.Model):
...
class B(models.Model):
属性 = models.OneToOneFiele(A, on_delete=xxx)
特殊字段选项【必须】
on_delete - 级联删除
- models.CASCADE级联删除。Django模拟SQL约束ON DELETE CASCADE的行为,并删除包括ForeignKey的对象。
- models.PROTECT抛出ProtectedError以阻止被引用对象的删除;【等同于MySQL默认的RESTRICT】
- SET_NULL设置ForeignKey null; 需要制定null=True
- SET_DEFAULT将ForeignKey设置为其默认值,必须设置ForeignKey的默认值
官方文档:https://docs.djangoproject.com/en/2.2/ref/models/fields/#foreignkey
示例:创建模型类 oto/models.py
from django.db import models
# Create your models here.
class Author(models.Model):
# 作家模型类
name = models.CharField('作家', max_length=11)
class Wife(models.Model):
# 作家妻子模型类
name = models.CharField('妻子', max_length=11)
author = models.OneToOneField(Author, on_delete=models.CASCADE) # 增加一对一属性
以外键字段名_id
作为字段名
无外键的模型类【Author】:
author1 = Author.objects.create(name = '王老师')
有外键的模型类【Wife】:
用类属性名:
wife1 = Wife.objects.create(name = '王夫人', author = author1) # 关联王老师obj
外键字段名:
wife1 = Wife.objects.create(name = '王夫人', author_id = 1) # 关联王老师对应主键值
查询数据
-
正向查询:直接通关外键属性查询,则成为正向查询
# 通过wife找author from .models import wife wife = wife.objects.get(name = '王夫人') print(wife.name, '的老公是', wife.author.name)
-
反向查询:没有外键属性的一方,可以调用反向属性查询到关联的另一方
反向关联属性为
实例对象.引用类名(小写)
,如作家的反向引力为作家对象.wifi
当反向引力不存在时,则会触发异常
author1 = Author.objects.get(name='王老师') author1.wife.name
三、一对多映射
一对多是表示现实事物间存在的一对多的对应关系。
如:一个学校有多个班级,一个班级有多个学生,一个图书只能属于一个出版社,一个出版社允许出版多本图书
一对多需要明确出具体角色,在多表上设置外键
语法:当一个A类对象可以关联多个B类对象时
class A(models.Model):
...
class B(models.Model):
属性 = models.ForeignKey("一"的模型类, on_delete=xx)
ForeignKry必须指定on_delete模式
示例:创建模型类 otm/models.py
# file : otm/models.py
from django.db import models
class Publish(models.Model):
# 出版社【一】
name = models.CharField('名称', max_length=50, unique=True)
class Book(models.Model):
# 书【多】
title = models.CharField('书名', max_length=50, on_delete=models.CASCADE)
先创建’一’ 再创建’多’
from .models import *
pub1 = Publisher.objects.create(name = '清华大学出版社')
Book.objects.create(title = 'C++', publisher = pub1)
Book.objects.create(title = 'Java', publisher_id = 1)
查询数据
-
正向查询【通过Book查询Publisher,通过publisher属性查询即可】
book.publisher abook = Book.objects.get(id=1) print(abook.title, '的出版社是:', abook.publisher.name)
-
反向查询【通过Publisher查询对应的所有的Book】
需要用到反向属性
# 通过出版社查询对应的书 pub1 = Publisher.objects.get(name='清华大学出版社') books = pub1.book_set.all() # 通过book_set获取pub1对应的多个Book数据对象 # books = Book.objects.filter(publisher=pub1) # 也可以采用此方式获取 print("清华大学出版社的书有:") for book in books: print(book.title)
四、多对多映射
多对多表达对象之间多对多复杂关系,如:每个人都有不同的学校(小学、初中、高中…),每个学校都有不同的学生
- MySQL中创建多对多需要依赖第三张表来表现
- Django中无需手动创建第三张表,Django自动完成
语法:在关联的两个类中的任意一个类中,增加
- 属性 = models.ManyToManyField(MyModel)
用法示例:
一个作者可以出版多本图书
一本图书可以被多名作者同时编写
class Author(models.Model):
...
class Book(models.Model):
...
authors = models.ManyToManyField(Author)
查询数据
-
正向查询 有多对多属性的对象 查另一方
通过 Book 查询所对应的所有 Author
此时多对多属性等价于objects
book.authors.all() → 获取book对应的所有的author的信息 book.authors.filter(age__gt=80) → 获取book对应的做这种年龄大于80岁的作者的信息
-
反向查询
利用Author查询对应的所有Book
利用反向属性Book_set
author.book_set.all() author.book_set.filter()