关系映射
文章目录
在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见关系映射有:
一对一映射
- 如:一个身份证对应一个人
一对多映射
- 如:一个班级可以有多个学生
多对多映射
- 如:一个学生可以报多个课程,一个课程可以有多个学生学习
一对一映射
一对一是表示现实事物间存在的一对一的对应关系。
- 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
语法:
OneToOneField(类名,on_delete=xxx)
on_delete 级联删除时要执行的操作
models.CASCADE
- 删除所有包含这个键的对象
- Django模拟SQL约束
ON DELETE CASCADE
的行为,删除包含ForeignKey
的所有对象
models.PROTECT
- 如果其他表引用到了这个外键默认不允许删除
modeIs.PROTECT
抛出ProtectedError
以阻止被引用对象的删除 [等同于mysq|默认的RESTRICT]
SET_NULL
- 如果想要删除这个外键,那么其他引用了这个外键的值都会被设置为 Null
- 有一个前提条件,就是被设置 null 的那个引用数据者本身需要能设置为 null(null=True)
SET_DEFAULT
SET_ DEFAULT
将ForeignKey
设置为其默认值- 必须设置
ForeignKey
的默认值。
class A(model.Model): ... class B(model.Model): 属性 = models.OneToOneField(A, on_delete=xxx)
实例
- 创建一个作者和他们老婆的表
迁移数据库
migrations
和migrate
[这里跳过]发现我们的外键名字发生了改变,并非是我们命名的
author
而是author_id
如何创建一个数据?
无外键的情况(正常创建)
author1 = Author.objects.create(name='王老师')
有外键的情况下
# 方案一:关联王老师 obj # 此处的 author 需要等于一个 实例化的 obj 对象 wife1 = Wife.objects.create(name='王夫人',author=author1)
方案二:关联王老师对应的主键
此处 author_id 直接等于一个值即可
wife1 = Wife.objects.create(name='王夫人',author_id=1)
方案一
方案二
- 此处我们
author_id
也可以等于a2.id
查询数据
正向查询:直接通过外键属性进行查询
# 通过 wife 找 author from .models import wife
wife = wife.objects.get(name="王夫人")
print(wife.name,"的老公是", wife.author.name)
反向查询:没有外键属性的一方,可以调用反向属性查询到关联的另一方
反向关联属性为
实例对象.应用类名(小写)
比如作家的反向引用为作家对象.wife
当反向引用不存在的时候会触发异常
# 通过author 找 wife from .models import Author
author1 = Author.objects.get(name="王老师")
print(author1.name,"的老婆是", author1.wife.name)
一对多映射
- 一对多是表示现实事物间存在的一对多的对应关系。
- 如:一个学校有多个班级,一个班级有多个学生,一本图书只能属于一 个出版社,一个出版社允许出版多本图书
- 一对多需要明确出具体角色,在多表上设置外键
创建映射
语法
当一个A类对象可以关联多个B类对象的时候
class A(model.Model): pass
class B(model.Model):
属性 = models.ForeignKey( A模型类, on_delete=XXX) #ForeignKey 必须指定on_delete
创建数据
先创建
一
,再创建多
from .models import *
pub1 = Publisher.objects.create(name="清华大学出版社")
使用方法一创建
Book.objects.create(title="C++",Publisher=pub1)
使用方法二创建
Book.objects.create(title="Java",Publish_id=1)
查询数据
正向查询[通过 Book 查询 Publisher]
abook = Book.objects.get(id=1) print(abook.title, "的出版社是",abook.publisher.name)
反向查询 book_set [通过Publisher查询对应的所有的Book]
pub1 = Publisher.objects.get(name="清华大学出版社")
通过 book_set 方法获取 pub1 对应的多个Book数据对象
books = pub1.book_set.all()
print("清华大学出版社的书有:")
for book in boos:
print(book.title)
多对多映射
多对多表达对象之间多对多复杂关系,如:每个人都有不同的学校( 小学,初中,高中..),每个学校都有不同的学生
- mysql中创建多对多需要依赖第三张表来实现
- Django中无需手动创建第三张表,Django 自动完成
语法:在关联的两个类中的任意一个类中,增加:
属性=models.ManyToManyField(MyModel)
创建映射
一个作者可以出版多本书
一本书可以被多个作者联名编写
class Author(models.Model): pass
class Book(models.Model):
authors = models.ManyToManyField(Author)
创建数据
方案一 先创建 author 再关联 book
author1 =Author.objects.create(name="王老师") author2 =Author.objects.create(name="吕老师")
两位老师同时写了一本书
book11 = author1.book_set.create(title="Python")
author2.book_set.add(book11)
方案二 先创建 book 再关联 author
# 书登场 book = Book.objects.create(title="python")
创建两位老师
author1 =Author.objects.create(name="王老师")
author2 = book.authors.create(name="吕老师")两位老师都参与了 python 的编写
book.authors.add(author1)
查询数据
正向查询 有多对多属性的对象查另外一遍
通过 Book 查询对应的所有 Author,此时多对多属性等价于 objects
# 获取book对应的所有的author的信息 book.authors.all()
获取book对应的作者中年龄大于80岁的作者的信息
book.authors.filter(age__ gt=80)
反向查询
通过 Author 查询对应的所有的 Book,利用反向属性
book_set
author.book_set.all( ) author.book_set.filter( )