在关系型数据库中,通常不会把所有数据都放在同一张表中,这样做会额外占用内存空间,
在关系列数据库中通常用表关联来解决数据库。
常用的表关联方式有三种:
- 一对一映射
如: 一个身份证对应一个人 - 一对多映射
如: 一个班级可以有多个学生 - 多对多映射
如: 一个学生可以报多个课程,一个课程可以有多个学生学习
一对一映射
-
语法
OneToOneField
class A(model.Model): ... class B(model.Model): 属性 = models.OneToOneField(A)
-
用法示例
创建男人和妻子类# file : xxxxxxxx/models.py from django.db import models class Man(models.Model): '''男人模型类''' name = models.CharField('姓名', max_length=50) class Wife(models.Model): '''妻子模型类''' name = models.CharField("姓名", max_length=50) husband = models. (Man) # 增加一对一属性
-
创始一对一的数据记录
from . import models man1 = models.Man.objects.create(name='王先生') wife1 = models.Wife.objects.create(name='王夫人', husband=man1) # 关联王老师 man2 = models.Man.objects.create(name='隔壁老王') # 一对一可以没有数据对应的数据
-
一对一数据的相互获取
在Wife
对象中,通过husband
属性找到对应的Man
对象
在Author
对象中,通过wife
属性找到对应的Wife
对象 -
正向查询
直接通过关联属性查询即可# 通过 wife 找 Man from . import models wife = models.Wife.objects.get(name='王夫人') print(wife.name, '的老公是', wife.husband.name)
-
反向查询
通过反向关联属性查询
反向关联属性为实例对象.引用类名(小写)
,如男人的反向引用为男人对象.wife
当反向引用不存在时,则会触发异常
# 通过 man.wife 关联属性 找 wife,如果没有对应的wife则触发异常 man1 = models.Man.objects.get(name='王先生') print(man1.name, '的妻子是', man1.wife.name) man2 = models.Man.objects.get(name='隔壁老王') try: print(man2.name, '的妻子是', man2.wife.name) except: print(man2.name, '还没有妻子')
-
作用:
主要是解决常用数据与不常用数据的存储问题,
把经常加载的一个数据放在主表中,不常用数据放在另一个副表中。
这样在访问主表数据时不需要加载副表中的数据以提高访问速度提高效率和节省内存空间,
如经常把书的内容和书名建成两张表,因为在网站上经常访问书名等信息,但不需要得到书的内容。
一对多映射
-
用法语法
ForeignKey
当一个A类对象可以关联多个B类对象时class A(model.Model): ... class B(model.Model): a = models.ForeignKey(A)
-
外键类
ForeignKey
构造函数:ForeignKey(to, on_delete, **options)
参数to
关联的主类on_delete
models.CASCADE
级联删除。 Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象。
models.PROTECT
抛出ProtectedError
以阻止被引用对象的删除;
SET_NULL
设置ForeignKey
值为null
;需要指定该列null=True
SET_DEFAULT
将ForeignKey
设置为其默认值;必须设置ForeignKey的默认值
。
其它参请参考文档 https://docs.djangoproject.com/en/1.11/ref/models/fields/#foreignkey**options
可以是常用的字段选项如:null
,unique
等
-
示例
有二个出版社对应五本书的情况.
清华大学出版社
有书(C++,Java,Python)
北京大学出版社
有书(西游记,水浒)-
定义一对多类
# file: one2many/models.py from django.db import models class Publisher(models.Model): '''出版社''' name = models.CharField('名称', max_length=50, unique=True) class Book(models.Model): title = models.CharField('书名', max_length=50) publisher = models.ForeignKey(Publisher, null=True)
-
创建一对多的对象
# file: xxxxx/views.py from . import models pub1 = models.Publisher.objects.create(name='清华大学出版社') models.Book.objects.creat e(title='C++', publisher=pub1) models.Book.objects.create(title='Java', publisher=pub1) models.Book.objects.create(title='Python', publisher=pub1) pub2 = models.Publisher.objects.create(name='北京大学出版社') models.Book.objects.create(title='西游记', publisher=pub2) models.Book.objects.create(title='水浒', publisher=pub2)
-
查询:
通过多查一
通过publisher
属性查询即可# 通过一本书找到对应的出版社 abook = models.Book.objects.get(id=1) print(abook.title, '的出版社是:', abook.publisher.name)
通过
一查多
通过book_set()
,管理器对象# 通过出版社查询对应的书 pub1 = models.Publisher.objects.get(name='清华大学出版社') books = pub1.book_set.all() # 通过book_set 获取pub1对应的多个Book数据对象 # books = models.Book.objects.filter(publisher=pub1) # 也可以采用此方式获取 print("清华大学出版社的书有:") for book in books: print(book.title)
-
多对多映射
多对多表达对象之间多对多复杂关系,如: 每个人都有不同的学校(小学,初中,高中,…),每个学校都有不同的学生…
-
语法
ManyToManyField
-
示例
一个作者可以出版多本图书
一本图书可以被多名作者同时编写class Author(models.Model): ... class Book(models.Model): ... authors = models.ManyToManyField(Author)
-
数据查询
通过Book
查询对应的所有的Authors
book.authors.all() -> 获取 book 对应的所有的author的信息 book.authors.filter(age__gt=80) -> 获取book对应的作者中年龄大于80岁的作者的信息
通过
Author
查询对应的所有的Books
Django会生成一个关联属性book_set
用于表示对对应的book
的查询对象相关操作author.book_set.all() author.book_set.filter() author.book_set.create(...) # 创建新书并联作用author author.book_set.add(book) # 添加已有的书为当前作者author author.book_set.clear() # 删除author所有并联的书
-
示例:
多对多模型class Author(models.Model): '''作家模型类''' name = models.CharField('作家', max_length=50) def __str__(self): return self.name class Book(models.Model): title = models.CharField('书名', max_length=50) author = models.ManyToManyField(Author) def __str__(self): return self.title
多对多视图操作
from django.http import HttpResponse from . import models def many2many_init(request): # 创建两人个作者 author1 = models.Author.objects.create(name='吕泽') author2 = models.Author.objects.create(name='王老师') # 吕择和王老师同时写了一本Python book11 = author1.book_set.create(title="Python") author2.book_set.add(book11) # # 王老师还写了两本书 book21 = author2.book_set.create(title="C") # 创建一本新书"C" book22 = author2.book_set.create(title="C++") # 创建一本新书"C++" return HttpResponse("初始化成功") def show_many2many(request): authors = models.Author.objects.all() for auth in authors: print("作者:", auth.name, '发出版了', auth.book_set.count(), '本书: ') for book in books: print(' ', book.title) print("----显示书和作者的关系----") books = models.Book.objects.all() for book in books: auths = book.author.all() print(book.title, '的作者是:', '、'.join([str(x.name) for x in auths])) return HttpResponse("显示成功,请查看服务器端控制台终端")
实际开发中,对于多对多的关系,在数据库设计层面,一般都会使用中间表来处理。
中间表中以外键的方式(一对多)关联两个多方。
同样的,在Django中也可以使用中间模型类来处理。