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.目前只剩 书籍表和 书籍作者表没创建信息。

image

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}]>

image

反向

  • 不许点author完成该题
# 反向  						拿作者姓名是objk的作者详情
res = models.AuthorDetail.objects.filter(author__name='objk').values('phone','author__name')
print(res)  

image

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)

image

6.总结:双下划线的跨表查询
你只要掌握了正反向的概念
以及双下划线
那么你就可以无限制的跨表
posted @ 2022-03-03 14:54  AlexEvans  阅读(300)  评论(0编辑  收藏  举报