Django | ORM多表操作
多表操作前期准备
models.py
class Book(models.Model):
name = models.CharField(max_length=32,verbose_name='书名')
price = models.DecimalField(max_digits=8,decimal_places=2,verbose_name='价格')
publish_date = models.DateTimeField(auto_now_add=True,verbose_name='出版时间')
publish = models.ForeignKey('Publish') # 一对多
authors = models.ManyToManyField('Author') # 多对多
class Publish(models.Model):
name = models.CharField(max_length=32,verbose_name='出版社名字')
addr = models.CharField(max_length=32,verbose_name='出版社地址')
class Author(models.Model):
name = models.CharField(max_length=32,verbose_name='作者名字')
age = models.IntegerField(verbose_name='作者年龄')
author_detail = models.OneToOneField('AuthorDetails') # 一对一
class AuthorDetails(models.Model):
phone = models.BigIntegerField(verbose_name='作者电话')
addr = models.CharField(max_length=32,verbose_name='作者地址')
一对多的外键增删改查
# 一对多外键增加数据
# 方式一:直接写实际字段
models.Book.objects.create(name='红楼梦',price=111.11,publish_id=1)
# 方式二:虚拟字段
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(name='三国演义',price=22.5,publish=publish_obj)
# 一对多外键删除数据
models.Pulish.objects.filter(pk=1).delete()
# 删除记录是级联删除的,所以对应的外键字段一会直接删除,取消关联关系
# 一对多外键修改数据
# 方式一:直接写实际字段
models.Book.objects.filter(pk=1).update(publish_id=2)
# 方式二:虚拟字段
publist_obj = models.Publish.objects.filter(pk=3).first()
models.Book.objects.filter(pk=2).update(publish=publist_obj)
多对多外键增删改查:
# 多对多的增删改查其实就是在操作第三张虚拟表
# 如何添加作者
# 这张表不是我们自己创建的是系统帮助我们创建的,所以我们根本不能通过models的方法(.)到这张表
# 这里就要通过对象(.)外键的方式找到第三张表
# 多对多表关系的增加:
# 关键字:.add(主键值)
# 方式一:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1)
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()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1,author_obj2) # 增加多个
# 多对多表关系的删:
# 关键字:.remove(主键值)
# 方式一:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(2,3) # 同样支持多条数据同时删除
# 方式二:对象
book_obj1 = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj1.authors.remove(author_obj1,author_obj2)
# 多对多表关系的修改
# 关键字:set()
# 方式一:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([2,3]) # 同样支持多条数据同时修改
# 方式二:对象
book_obj1 = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj1.authors.set([author_obj1,author_obj2])
# 注意:set关键字括号内必须填写一个可迭代对象(列表或者元组)
# 多对多表关系的清空(清空在第三中某个书籍与作者的绑定关系)
# 关键字:clear() # 括号内不要加任何参数
正反向查询概念
# 通过查看外键的位置来判断是正向查询还是反向查询
# 正向查询:外键字段在A表里 ,A查B表就是正向查询
# 反向查询:那么B查A表就是反向查询
# eg:
Book(外键字段在这里) >> Publish # 正向查询
Publist(外键字段不在这里) >> Book # 反向查询
通过正反向的概念我们再来研究跨表查询。
多表查询
引子:
# 正向查询按 字段(外键字段)
# 反向查询按 表名小写_set
# 注意:
在书写orm语句的时候跟写sql语句一样的
不要企图一次性将orm语句写完 如果比较复杂 就写一点看一点
子查询(基于对象的跨表查询)
# 查找主键值为1的书的出版社名字和出版社地址(正向)
book_obj = models.Book.objects.filter(pk=1).first() # 先拿到主键为1的书籍对象
res = book_obj.publish # 拿到外键字段所对应关系表中的对象
print(res) # 对应出版社的对象
print(res.name) # 出版社名字
print(res.addr) # 出版社地址
# 查询书籍主键为2的作者(正向)
book_obj = models.Book.objects.filter(pk=2).first()
res = book_obj.authors #
print(res)
# 我们发现返回了一个:app01.Author.None
# 注意这个返回结果是一个标志性的问题:在当返回结果可能为多个的时候(一本书可以由多名作者编写(多对多的表关系)必须加关键字.all())
# # 查询书籍主键为2的作者(正向)
book_obj = models.Book.objects.filter(pk=2).first()
res = book_obj.authors.all()
print(res)
print(res[0].name) # 因对象有多个所以要通过索引取值拿到单独的对象
print(res[1].name)
# 查询作者gary的电话号码(正向)
author_obj = models.Author.objects.filter(name='gary').first()
print(author_obj)
res = author_obj.author_detail
print(res)
print(res.phone)
print(res.addr)
# 查询是南方出版社出版的书(无外键字段(反向))
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
res = publish_obj.book
print(res)
# 反向查询上边有提到需要加入_set
# 查询是南方出版社出版的书(无外键字段(反向))
publish_obj = models.Publish.objects.filter(name='南方出版社').first()
res = publish_obj.book_set.all() # 并且使用到.all()方法
print(res)
# 5.查询作者是jason写过的书
author_obj = models.Author.objects.filter(name='jason').first()
res = author_obj.book_set.all()
print(res)
# 6.查询手机号是110的作者姓名
authorsetails_obj = models.AuthorDetails.objects.filter(phone='110').first()
res1 = authorsetails_obj.author
print(res1)
总结
# 基于对象
反向查询的时候
当你的查询结果可能有多个的时候 就必须加_set.all()
当你的结果只能有一个的时候 不需要加_set.all()
联表查询(基于双下划线的跨表查询)
# 同样遵循
# 正向查询按字段
# 反向查询按表名小写
习题:
# 查询作者gary的手机号(必须用一行代码展示)
res = models.Author.objects.filter(name='gary').values('author_detail__phone','name')
print(res)
# 利用values方法查询
注意:此时Author为基表可通过values方法直接查到该表的属性值
# 反向:(不允许.Author)
res = models.AuthorDetails.objects.filter(author__name='gary').values('phone','author__name')
print(res)
# 查询书籍主键为1的出版社的名称和书的名称
res = models.Book.objects.filter(pk=1).values('name','publish__book')
print(res)
# 方式二:反向
res = models.Publish.objects.filter(book__id='1').values('name','book__name')
print(res)
# 3.查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk=1).values('authors__name')
print(res)
# 方式二:反向
res = models.Author.objects.filter(book__id=1).values('name')
print(res)
最终练习:
# 查询书籍主键是1的作者的手机号
# 注意:这道题涉及到三张表
# 思路:通过书籍查作者,再通过作者查作者详情
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)