关系映射
在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见的关系映射有:
-
一对一映射,如一个身份证对应一个人。
-
一对多映射,如一个班级可以有多个学生。
-
多对多映射,如一个学生可以报多个课程,一个课程可以有多个学生学习。
1 一对一映射
1.1 一对一映射定义
-
一对一是表示现实事物间存在的一对一的对应关系。如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的身份证号等。
1.2 一对一映射创建模型
-
语法:OneToOneField(类名,on_delete=xxx),on_delete:级联删除。
class A(model.Model):... class B(model.Model):属性 = models.OneToOneField(A, on_delete=xxx)
-
特殊字段选项【必须】,on_delete,级联删除。
Django中的一对一映射
-
models.CASCADE 级联删除,Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForegnKey的对象。
-
models.PROTECT 抛出ProtectedError 以组织被引用对象的删除,等同于 mysql 默认的RESTRICT。
-
SET_NULL 设置 ForeignKey null,需要指定 null=True;
-
SET_DEFAULT 将 ForeignKey 设置为其默认值,必须设置ForeignKey默认值。
代码示例:
from django.db import models
# 关系说明:一个人只有一个身份证号码,一个身份证号码对应一个人
# Create your models here.
class Person(models.Model):"""个人类"""name = models.CharField("姓名", max_length=11, default='', null=False)age = models.IntegerField("年龄", default=1)home = models.CharField("住址", max_length=256, default='')
def __str__(self):return "%s_%s_%s" % (self.name, self.age, self.email)
class IdCard(models.Model):"""身份证件"""idCardNUmber = models.CharField("身份证号码", max_length=32, null=False)person = models.OneToOneField(Person, on_delete=models.CASCADE) # 一对一属性
1.3 一对一映射创建数据
# 无外键的模型类[Person]:
person = Person.objects.create(name='南歌', age=20, home='陕西省延安市')
# 有外键的模型类[IdCard]
idcard = IdCard.objects.create(idCardNUmber='xxxx', person=person)
# 也即关联个人的主键值
idcard = IdCard.objects.create(idCardNUmber='xxxx', person_id=person_id)
直接关联外键对应的对象。
数据库查看。
关联外键对应对象的主键值。
数据库查看。
1.4 一对一映射查询数据
-
正向查询:直接通过关联的外键属性查询,则称为正向查询。
# 通过IdCard查找Person from oto.models import * idCard = IdCard.objects.get(idCardNUmber='xxxx') print("身份证号:{idCardNUmber}的人姓名为:{name}".format(idCardNUmber=idCard.idCardNUmber, name=idCard.person.name))
-
反向查询:没有外键属性的一方,可以调用反向属性查询到关联的另一方。
注:
-
反向关联属性为
实例对象.引用类名(小写)
,如个人的反向引用为个人对象.idcard
。 -
当反向引用不存在时,则会触发异常。
# 通过IdCard查找Person from oto.models import * person = Person.objects.get(name='南歌') person.idcard.idCardNUmber
反向属性不存在时,触发异常。
-
2 一对多映射
2.1 一对多映射定义
-
一对多是表现现实事物间存在的一对多的对应关系。如:一个学校有多个班级,一个班级有多个学生,一本图书只能属于一个出版社,一个出版社允许出版多本图书。
-
一对多需要明确出具体角色,在多表上设置外键。
2.2 一对多映射创建模型
-
语法
# 当一个A类对象可以关联多个B类对象时 class A(models.Model):...class B(models.Model):属性 = models.Foreignkey("一"的模型类, on_delete=xx) # Fortignkey 必须指定 on_delete模式
代码示例:
from django.db import models
# Create your models here.
# 关系说明:一个出版社可以有多本图书,一个图书只能对应一个出版社
class Press(models.Model):"""出版社"""name = models.CharField("名称", max_length=128, unique=True)
class Book(models.Model):"""图书"""name = models.CharField("书名", max_length=128)press = models.ForeignKey(Press, on_delete=models.CASCADE)
2.3 一对多映射创建数据
# 先创建一,再创建多
from otm.models import *
press = Press.objects.create(name="东北大学出版社")
Book.objects.create(name="C++教程", press=press)
Book.objects.create(name="Python教程", press_id=press_id)
2.4 一对多映射查询数据
-
正向查询:直接通过关联的外键属性查询,则称为正向查询。
# 通过Book查找Press from otm.models import * book = Book.objects.get(name='Python教程') print("{book}的出版社是{name}".format(book=book.name, name=book.press.name))
-
反向查询:没有外键属性的一方,可以调用反向属性查询到关联的另一方。
# 通过 Press 查找 Book from otm.models import * press = Press.objects.filter(name='东北大学出版社') books = press.book_set.all()
3 多对多映射
3.1 多对多定义
-
多对多表达对象之间多对多复杂关系,如:每个人都有不同的学校(小学,初中,高中,...),每个学校都有不同的学生...
-
Mysql中创建多对多需要依赖第三张表来实现。
-
Django中无需手动创建第三张表,Django自动完成。
3.2 多对多映射创建模型
-
语法:在关联的两个类中的任意一个类中增加:
属性 = models.ManyToManyField(MyModel)
-
代码示例:
# 关系说明:一个作者可以出版多本图书,一本图书可以被多名坐着同时编写 from django.db import models # Create your models here. class Author(models.Model):name = models.CharField("作者", max_length=128) class Book(models.Model):name = models.CharField("书名", max_length=128)authors = models.ManyToManyField(Author)
3.3 多对多映射创建数据
# 方案一:先创建author再关联book
author1 = Author.objects.create(name="南歌")
author2 = Author.objects.create(name="EuanSu")
## 南歌和EuanSu同时写了一本《Django教程》
book = author1.book_set.create(name="Django教程")
author2.book_set.add(book)
# 方案二:先创建book再关联author
book = Book.objects.create(name="Python教程")
## 南歌和EuanSu都参与了《Python教程》的编写
author = book.authors.create(name="南歌")
book.authors.add(author)
3.4 多对多映射查询数据
-
正向查询:直接通过关联的外键属性查询,则称为正向查询。
# 通过Book查询对应所有的 Author,此时多对多属性等价于objects ## 获取 book 对应的所有author信息 book.authors.all() ## 获取book对应作者中名字为南歌的author book.authors.filter(name="南歌")
-
反向查询:没有外键属性的一方,可以调用反向属性查询到关联的另一方。
# 通过Author查询对应所有的book,利用反向属性book_set author.book_set.all() author.book_set.filter(name="Django教程")