Django框架表关系外键-多对多外键(增删改查)-正反向的概率-多表查询(子查询与联表查询)
一:表关系外键
1.提前创建表关系
from django import models
# 书籍
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_data = models.DateField(auto_now_add=True)
# 一对多(出版社对书籍)
publish = models.ForeignKey(to='Publish')
# 多对多
authors = models.ManyToManyField(to='Author')
# 出版社
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
email = models.EmailField() # 该字段类型不是给models看的 而是给后面我们会学到的校验组件看的
# 作者
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
# 一对一
author_detail = models.OneToOneField(to='AuthorDetail')
# 作者详情
class AuthorDetail(models.Model):
phone = models.BigIntegerField() # 电话号码用BigIntegerField或者直接用CharField
addr = models.CharField(max_length=64)
2.目前只剩 书籍表和 书籍作者表没创建信息。
3.增
1.直接写实际字段 id
models.Book.objects.create(title='论语', price=899.23, publish_id=1)
2.虚拟字段 对象
出版社对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦', price=666.23, publish=publish_obj)
4.删
models.Publish.objects.filter(pk=1).delete() # 级联删除
5.修改
1.直接直接写实际字段 id
models.Book.objects.filter(pk=1).update(publish_id=2)
2.虚拟字段 对象
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
二:多对多外键增删改查
- 多对多 增删改查 就是在操作第三张关系表
1.给书籍绑定作者
书籍对象
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.authors) # 点authors就类似于你已经到了第三张关系表了
书籍id为1的书籍绑定一个主键为1 的作者
book_obj.authors.add(1)
书籍id为1的书籍绑定一个主键为2 和 主键为3 的作者
book_obj.authors.add(2, 3)
支持外键 对象
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
书籍id为1的书籍绑定一个主键为1 的作者
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1, author_obj2)
add给第三张关系表添加数据
括号内既可以传数字也可以传对象 并且都支持多个
2.删
书籍对象
book_obj = models.Book.objects.filter(pk=1).first()
书籍id为1删除 主键为2 的作者
book_obj.authors.remove(2)
支持作者对象
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=3).first()
删除 书籍id为1 作者主键为1和3 的 作者
book_obj.authors.remove(author_obj, author_obj1)
remove
括号内既可以传数字也可以传对象 并且都支持多个
3.修改
书籍对象
book_obj = models.Book.objects.filter(pk=1).first()
将书籍id为1 关联的作者主键id修改成2
book_obj.authors.set([2]) # 括号内必须给一个可迭代对象
将书籍id为1 关联的作者主键id修改成 1 和 2
book_obj.authors.set([2, 3]) # 括号内必须给一个可迭代对象
支持作者对象
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=3).first()
set
括号内必须传一个可迭代对象 该对象内既可以书籍也可以对象 并且都支持多个
1.先删除后新增
2.如果值存在 就不动
4.清空
书籍对象
book_obj = models.Book.objects.filter(pk=1).first()
在第三张关系表中清空某个书籍于作者的绑定关系
book_obj.authors.clear()
clear
括号内什么参数都不要加
三:正反向的概念
1.什么是正向?
外键字段在我手上那么,我查你就是正向
2.什么是反向?
外键字段如果不在手上,我查你就是反向
3.判断正向反向
book >>>外键字段在书那儿(正向)>>> publish
publish >>>外键字段在书那儿(反向)>>>book
一对一和多对多正反向的判断也是如此
4.查询方式
正向查询:
按外键字段
反向查询按:
表名小写加_set
当你的查询结果有多个的时候就需要加.all()
如果是一个则直接拿到数据对象
5.应用场景.all()
1.书籍只能对应一个出版社 不需要.all()
2.书籍可以有可以作者 需要.all()
3.作者只能有一个作者详细信息 不需要.all()
四:多表查询
1.子查询与联表查询
多表查询分为
子查询:
基于对象的跨表查询
联表查询:
基于双下划线的跨表查询
五:子查询(基于对象的跨表查询)
1.子查询(正向)
eg:子查询就是分布操作
1.查询书籍为1的出版社名称
获取书籍对象
book_obj = models.Book.objects.filter(pk=1).first()
书查出版社 正向 按照字段查询
res = book_obj.publish
print(res) # 对象:东方出版社
print(res.name) # 东方出版社
print(res.addr) # 东方
2.查询书籍主键为2的作者
book_obj = models.Book.objects.filter(pk=2).first()
书查作者 正向
res = book_obj.authors # app01.Author.None 当拿到的结果是该结果 没有错 只是少了一个all()
res = book_obj.authors.all()
拿到书籍两个作者 <QuerySet [<Author: Author object>, <Author: Author object>]>
print(res)
3.查询作者objk的电话号码
1.先获取作者对象
author_obj = models.Author.objects.filter(name='objk').first()
作者 查 作者详细信息
res = author_obj.author_detail
print(res) # 详情信息对象 AuthorDetail object
print(res.phone) # 110
2.子查询(正向)总结
在书写orm语句的时候跟写sql语句一样的
不要企图一次性将orm语句写完 如果比较复杂 就写一点看一点
正向什么时候需要加.all()
当你的结果可能有多个的时候就需要加.all()
如果是一个则直接拿到数据对象
应用场景:
1.书籍只能对应一个出版社 不需要.all()
book_obj.publish
2.书籍可以有可以作者 需要.all()
book_obj.authors.all()
3.作者只能有一个作者详细信息 不需要.all()
author_obj.author_detail
3.子查询(反向)
4.查询出版社是东方出版社出版的书
先查询出版社
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
出版社查书 反向 表名小写_set
res = publish_obj.book_set # app01.Book.None 该情况使用all()
res = publish_obj.book_set.all() # <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]>
print(res.title)
5.查询作者是objk写过的书
先获取作者对象
author_obj = models.Author.objects.filter(name='objk').first()
作者 查书籍 反向
res = author_obj.book_set.all()
print(res) # <QuerySet [<Book: Book object>]>
6.查询手机号是110的作者姓名
作者 查 作者详情 反向
先拿作者详情手机号为110对象
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
res = author_detail_obj.author
print(res.name) # objk
4.子查询(反向)
基于对象
反向查询的时候
当你的查询结果可以有多个的时候 就必须加_set.all()
当你的结果只有一个的时候不需要加_set.all()
六:联表查询(基于双下划线的跨表查询)
- 基于双下划线的跨表查询
1.values作用
values可以放多个字段
1.既可以用单选表的字段
2.也可以用跨表查询的特点
3.利用正反向概率跨表,然后取字段
2.filter作用
filter同样支持正反向的概念
2.查询objk的手机号 (一行代码搞定)
# 正向查询 按照字段 author_detail跨表查询双下划线phone 取字段
res = models.Author.objects.filter(name='objk').values('author_detail__phone', 'nmae')
print(res)
# <QuerySet [{'author_detail__phone': 110}]>
反向
- 不许点author完成该题
# 反向 拿作者姓名是objk的作者详情
res = models.AuthorDetail.objects.filter(author__name='objk').values('phone','author__name')
print(res)
3.查询书籍主键为1的出版社名和书的名称
res = models.Book.objects.filter(pk=1).values('title','publish__name')
print(res)
# <QuerySet [{'title': '三国演义', 'publish__name': '东方出版社'}]>
- 反向
res = models.Publish.objects.filter(book__id=1).values('name','book__title')
print(res)
# <QuerySet [{'name': '东方出版社', 'book__title': '三国演义'}]>
4.查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk=1).values('authors__name')
print(res)
# <QuerySet [{'authors__name': 'objk'}]>
- 反向
res = models.Author.objects.filter(book__id=1).values('name')
print(res)
# <QuerySet [{'name': 'objk'}]>
5.查询书籍主键是1的作者的手机号
需求:
该需求 涉及到 三张表 (book author author_detail)
# authors 作者表 authors__author_detail 作者详情表 authors__author_detail__phone 双下划线获取手机号字段
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
print(res)
6.总结:双下划线的跨表查询
你只要掌握了正反向的概念
以及双下划线
那么你就可以无限制的跨表