查询数据
- 数据库的查询需要使用管理器对象进行
- 通过 MyModel.objects 管理器方法调用查询接口
方法 说明 all() 查询全部记录,返回QuerySet查询对象 get() 查询符合条件的单一记录 filter() 查询符合条件的多条记录 exclude() 查询符合条件之外的全部记录 …
all()方法
- 方法: all()
- 用法: MyModel.objects.all()
- 作用: 查询MyModel实体中所有的数据
- 等同于
- select * from tabel
- 等同于
- 返回值: QuerySet容器对象,内部存放 MyModel 实例
- 示例:
1
2
3
4from bookstore.models import Book
books = Book.objects.all()
for book in books:
print("书名", book.title, '出版社:', book.pub)
在模型类中定义
def __str__(self):
方法可以自定义默认的字符串1
2
3
4class Book(models.Model):
title = ...
def __str__(self):
return "书名: %s, 出版社: %s, 定价: %s" % (self.title, self.pub, self.price)查询返回指定列(字典表示)
方法: values(‘列1’, ‘列2’)
用法: MyModel.objects.values(…)
作用: 查询部分列的数据并返回
- select 列1,列2 from xxx
返回值: QuerySet
- 返回查询结果容器,容器内存字典,每个字典代表一条数据,
- 格式为: {‘列1’: 值1, ‘列2’: 值2}
示例:
1
2
3
4
5from bookstore.models import Book
books = Book.objects.values("title", "pub")
for book in books:
print("书名", book["title"], '出版社:', book['pub'])
print("book=", book)
查询返回指定列(元组表示)
方法:values_list(‘列1’,’列2’)
用法:MyModel.objects.values_list(…)
作用:
- 返回元组形式的查询结果
返回值: QuerySet容器对象,内部存放
元组
- 会将查询出来的数据封装到元组中,再封装到查询集合QuerySet中
示例:
1
2
3
4
5from bookstore.models import Book
books = Book.objects.values_list("title", "pub")
for book in books:
print("书名", book[0], '出版社:', book[1])
print("book=", book) # ('Python', '清华大学出版社')...
排序查询
方法:order_by
用法:MyModel.objects.order_by(‘-列’,’列’)
作用:
- 与all()方法不同,它会用SQL 语句的ORDER BY 子句对查询结果进行根据某个字段选择性的进行排序
说明:
- 默认是按照升序排序,降序排序则需要在列前增加’-‘表示
示例:
1
2
3
4from bookstore.models import Book
books = Book.objects.order_by("price")
for book in books:
print("书名:", book.title, '定价:', book.price)
条件查询 - filter
方法: filter(条件)
语法:
1
MyModel.objects.filter(属性1=值1, 属性2=值2)
返回值:
- QuerySet容器对象,内部存放 MyModel 实例
说明:
- 当多个属性在一起时为”与”关系,即当
Books.objects.filter(price=20, pub="清华大学出版社")
返回定价为20且
出版社为”清华大学出版社”的全部图书
- 当多个属性在一起时为”与”关系,即当
示例:
1
2
3
4
5
6
7
8# 查询书中出版社为"清华大学出版社"的图书
from bookstore.models import Book
books = Book.objects.filter(pub="清华大学出版社")
for book in books:
print("书名:", book.title)
# 查询Author实体中name为王老师并且age是28岁的
authors=Author.objects.filter(name='王老师',age=28)
条件查询 - exclude
方法: exclude(条件)
语法:
- MyModel.objects.exclude(条件)
作用:
- 返回不包含此
条件
的 全部的数据集
- 返回不包含此
示例:
- 查询
清华大学出版社,定价等于50
以外的全部图书
1
2
3books = Book.objects.exclude(pub="清华大学出版社", price=50)
for book in books:
print(book)- 查询
条件查询 - get
方法: get(条件)
语法:
- MyModel.objects.get(条件)
作用:
- 返回满足条件的唯一一条数据
说明:
- 该方法只能返回一条数据
- 查询结果多余一条数据则抛出,Model.MultipleObjectsReturned异常
- 查询结果如果没有数据则抛出Model.DoesNotExist异常
示例:
1
2
3from bookstore.models import Book
book = Book.objects.get(id=1)
print(book.title)
查询谓词
- 每一个查询谓词是一个独立的查询功能
__exact
: 等值匹配1
2Author.objects.filter(id__exact=1)
# 等同于select * from author where id = 1__contains
: 包含指定值1
2Author.objects.filter(name__contains='w')
# 等同于 select * from author where name like '%w%'__startswith
: 以 XXX 开始__endswith
: 以 XXX 结束__gt
: 大于指定值1
2Author.objects.filer(age__gt=50)
# 等同于 select * from author where age > 50__gte
: 大于等于__lt
: 小于__lte
: 小于等于__in
: 查找数据是否在指定范围内- 示例
1
2Author.objects.filter(country__in=['中国','日本','韩国'])
# 等同于 select * from author where country in ('中国','日本','韩国')
- 示例
__range
: 查找数据是否在指定的区间范围内1
2
3# 查找年龄在某一区间内的所有作者
Author.objects.filter(age__range=(35,50))
# 等同于 SELECT ... WHERE Author BETWEEN 35 and 50;详细内容参见: https://docs.djangoproject.com/en/2.2/ref/models/querysets/#field-lookups
- 示例
1
2MyModel.objects.filter(id__gt=4)
# 等同于 SELECT ... WHERE id > 4;
修改数据
- 修改单个实体的某些字段值的步骤:
- 查
- 通过 get() 得到要修改的实体对象
- 改
- 通过 对象.属性 的方式修改数据
- 保存
- 通过 对象.save() 保存数据
- 如:
1
2
3
4from bookstore.models import Book
abook = Book.objects.get(id=10)
abook.market_price = "10.5"
abook.save()
- 查
- 通过 QuerySet 批量修改 对应的全部字段
直接调用QuerySet的update(属性=值) 实现批量修改
返回值:更新数据的数量
如:
1
2
3
4
5
6# 将id大于3的所有图书价格定为0元
books = Book.objects.filter(id__gt=3)
books.update(price=0)
# 将所有书的零售价定为100元
books = Book.objects.all()
books.update(market_price=100)
删除数据
- 删除记录是指删除数据库中的一条或多条记录
- 删除单个MyModel对象或删除一个查询结果集(QuerySet)中的全部对象都是调用 delete()方法
- 删除单个对象
- 步骤
- 查找查询结果对应的一个数据对象
- 调用这个数据对象的delete()方法实现删除
- 示例:
1
2
3
4
5try:
auth = Author.objects.get(id=1)
auth.delete()
except:
print(删除失败)
- 步骤
- 删除查询结果集
- 步骤
- 查找查询结果集中满足条件的全部QuerySet查询集合对象
- 调用查询集合对象的delete()方法实现删除
- 示例:
1
2
3# 删除全部作者中,年龄大于65的全部信息
auths = Author.objects.filter(age__gt=65)
auths.delete()
- 步骤
聚合查询
- 聚合查询是指对一个数据表中的一个字段的数据进行部分或全部进行统计查询,查bookstore_book数据表中的全部书的平均价格,查询所有书的总个数等,都要使用聚合查询
- 不带分组聚合
不带分组的聚合查询是指导将全部数据进行集中统计查询
聚合函数【需要导入】:
- 导入方法:
from django.db.models import *
- 聚合函数:
- Sum, Avg, Count, Max, Min
- 导入方法:
语法:
- MyModel.objects.aggregate(结果变量名=聚合函数(‘列’))
返回结果:
- 由 结果变量名和值组成的字典
- 格式为:
- `{“结果变量名”: 值}
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13# 得到所有书的平均价格
from bookstore.models import Book
from django.db.models import Avg
result = Book.objects.aggregate(myAvg=Avg('price'))
print("平均价格是:", result['myAvg'])
print("result=", result) # {"myAvg": 58.2}
# 得到数据表里有多少本书
from django.db.models import Count
result = Book.objects.aggregate(mycnt=Count('title'))
print("数据记录总个数是:", result['mycnt'])
print("result=", result) # {"mycnt": 10}
- 分组聚合
分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
语法:
- QuerySet.annotate(结果变量名=聚合函数(‘列’))
用法步骤:
- 通过先用查询结果MyModel.objects.values 查找查询要分组聚合的列
- MyModel.objects.values(‘列1’, ‘列2’)
- 如:
1
2pub_set = Book.objects.values('pub')
print(pub_set) # <QuerySet [{'pub': '清华大学出版社'}, {'pub': '清华大学出版社'}, {'pub_hou {'pub': '机械工业出版社'}, {'pub': '清华大学出版社'}]>
- 通过返回结果的 QuerySet.annotate 方法分组聚合得到分组结果
- QuerySet.annotate(名=聚合函数(‘列’))
- 返回 QuerySet 结果集,内部存储结果的字典
- 如:
1
2pub_count_set = pub_set.annotate(myCount=Count('pub'))
print(pub_count_set) # <QuerySet [{'pub': '清华大学出版社', 'myCount': 7}, {'pub': '机械工业出版社', 'myCount': 3}]>
- 通过先用查询结果MyModel.objects.values 查找查询要分组聚合的列
示例:
- 得到哪儿个出版社共出版多少本书
1
2
3
4
5
6
7
8
9
10
11def test_annotate(request):
from django.db.models import Count
from . import models
# 得到所有出版社的查询集合QuerySet
pub_set = models.Book.objects.values('pub')
# 根据出版社查询分组,出版社和Count的分组聚合查询集合
pub_count_set = pub_set.annotate(myCount=Count('pub')) # 返回查询集合
for item in pub_count_set:
print("出版社:", item['pub'], "图书有:", item['myCount'])
return HttpResponse('请查看服务器端控制台获取结果')
- 得到哪儿个出版社共出版多少本书
F对象
- 一个F对象代表数据库中某条记录的字段的信息
作用:
- 通常是对数据库中的字段值在不获取的情况下进行操作
- 用于类属性(字段)之间的比较。
用法
- F对象在数据包 django.db.models 中,使用时需要先导入
from django.db.models import F
- F对象在数据包 django.db.models 中,使用时需要先导入
语法:
1
2from django.db.models import F
F('列名')说明:
- 一个 F() 对象代表了一个model的字段的值
- F对象通常是对数据库中的字段值在不加载到内存中的情况下直接在数据库服务器端进行操作
示例1
- 更新Book实例中所有的零售价涨10元
1
2
3
4
5
6
7Book.objects.all().update(market_price=F('market_price')+10)
'UPDATE `bookstore_book` SET `market_price` = (`bookstore_book`.`market_price` + 10)
# 以上做法好于如下代码
books = Book.objects.all()
for book in books:
book.market_price=book.marget_price+10
book.save()
- 更新Book实例中所有的零售价涨10元
示例2
- 对数据库中两个字段的值进行比较,列出哪儿些书的零售价高于定价?
1
2
3
4
5
6from django.db.models import F
from bookstore.models import Book
books = Book.objects.filter(market_price__gt=F('price'))
'SELECT * FROM `bookstore_book` WHERE `bookstore_book`.`market_price` > (`bookstore_book`.`price`)
for book in books:
print(book.title, '定价:', book.price, '现价:', book.market_price)
- 对数据库中两个字段的值进行比较,列出哪儿些书的零售价高于定价?
Q对象
当在获取查询结果集 使用复杂的逻辑或
|
、 逻辑非~
等操作时可以借助于 Q对象进行操作如: 想找出定价低于20元 或 清华大学出版社的全部书,可以写成
1
Book.objects.filter(Q(price__lt=20)|Q(pub="清华大学出版社"))
Q对象在 数据包 django.db.models 中。需要先导入再使用
from django.db.models import Q
作用
- 在条件中用来实现除 and(&) 以外的 or(|) 或 not(~) 操作
运算符:
- & 与操作
- | 或操作
- 〜 非操作
语法
1
2
3
4
5from django.db.models import Q
Q(条件1)|Q(条件2) # 条件1成立或条件2成立
Q(条件1)&Q(条件2) # 条件1和条件2同时成立
Q(条件1)&~Q(条件2) # 条件1成立且条件2不成立
...示例
1
2
3
4
5from django.db.models import Q
# 查找清华大学出版社的书或价格低于50的书
Book.objects.filter(Q(market_price__lt=50) | Q(pub_house='清华大学出版社'))
# 查找不是机械工业出版社的书且价格低于50的书
Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='机械工业出版社'))
原生的数据库操作方法
- 使用MyModel.objects.raw()进行 数据库查询操作查询
- 在django中,可以使用模型管理器的raw方法来执行select语句进行数据查询
语法:
MyModel.objects.raw(sql语句,[拼接参数])
用法
MyModel.objects.raw('sql语句', [拼接参数])
返回值:
- RawQuerySet 集合对象 【只支持基础操作,比如循环】
示例
1 | books = Book.objects.raw('select * from bookstore_book') |
- 使用django中的游标cursor对数据库进行 增删改查 操作
在Django中跨过模型类直接操作数据库
使用步骤:
- 导入cursor所在的包
- Django中的游标cursor定义在 django.db.connection包中,使用前需要先导入
- 如:
from django.db import connection
- 用创建cursor类的构造函数创建cursor对象,再使用cursor对象,为保证在出现异常时能释放cursor资源,通常使用with语句进行创建操作
- 如:
1
2
3from django.db import connection
with connection.cursor() as cur:
cur.execute('执行SQL语句', '拼接参数')
- 如:
- 导入cursor所在的包
示例
1
2
3
4
5
6
7
8
9# 用SQL语句将id 为 10的 书的出版社改为 "XXX出版社"
from django.db import connection
with connection.cursor() as cur:
cur.execute('update bookstore_book set pub_house="XXX出版社" where id=10;')
with connection.cursor() as cur:
# 删除 id为1的一条记录
cur.execute('delete from bookstore_book where id=10;')
admin 后台数据库管理
- django 提供了比较完善的后台管理数据库的接口,可供开发过程中调用和测试使用
- django 会搜集所有已注册的模型类,为这些模型类提拱数据管理界面,供开发者使用
- 使用步骤:
- 创建后台管理帐号:
- 后台管理–创建管理员帐号
$ python3 manage.py createsuperuser
- 根据提示完成注册,参考如下:
1
2
3
4
5
6
7python3 manage.py createsuperuser
Username (leave blank to use 'tarena'): tarena # 此处输入用户名
Email address: laowei@tedu.cn # 此处输入邮箱
Password: # 此处输入密码(密码要复杂些,否则会提示密码太简单)
Password (again): # 再次输入重复密码
Superuser created successfully.
- 后台管理–创建管理员帐号
- 用注册的帐号登陆后台管理界面
- 后台管理的登录地址:
- 创建后台管理帐号:
注册自定义模型类
- 若要自己定义的模型类也能在
/admin
后台管理界中显示和管理,需要将自己的类注册到后台管理界面 - 添加自己定义模型类的后台管理数据表的,需要用
admin.site.register(自定义模型类)
方法进行注册- 配置步骤如下:
- 在应用app中的admin.py中导入注册要管理的模型models类, 如:
1
from .models import Book
- 调用 admin.site.register 方法进行注册,如:
1
2from django.contrib import admin
admin.site.register(自定义模型类)
- 在应用app中的admin.py中导入注册要管理的模型models类, 如:
- 如: 在 bookstore/admin.py 添加如下代码对Book类进行管理
- 示例:
1
2
3
4
5
6
7# file: bookstore/admin.py
from django.contrib import admin
# Register your models here.
from . import models
...
admin.site.register(models.Book) # 将Book类注册为可管理页面
- 配置步骤如下:
修改自定义模型类的展现样式
- 在admin后台管理数据库中对自定义的数据记录都展示为
XXXX object
类型的记录,不便于阅读和判断 - 在用户自定义的模型类中可以重写
def __str__(self):
方法解决显示问题,如:- 在 自定义模型类中重写 str(self) 方法返回显示文字内容:
1
2
3
4class Book(models.Model):
...
def __str__(self):
return "书名" + self.title
- 在 自定义模型类中重写 str(self) 方法返回显示文字内容:
模型管理器类
作用:
- 为后台管理界面添加便于操作的新功能。
说明:
- 后台管理器类须继承自
django.contrib.admin
里的ModelAdmin
类
- 后台管理器类须继承自
模型管理器的使用方法:
- 在
<应用app>/admin.py
里定义模型管理器类1
2class XXXXManager(admin.ModelAdmin):
...... - 绑定注册模型管理器和模型类
1
2
3from django.contrib import admin
from .models import *
admin.site.register(YYYY, XXXXManager) # 绑定 YYYY 模型类与 管理器类 XXXXManager
- 示例:
1
2
3
4
5
6
7
8# file : bookstore/admin.py
from django.contrib import admin
from .models import Book
class BookManager(admin.ModelAdmin):
list_display = ['id', 'title', 'price', 'market_price']
admin.site.register(Book, BookManager)- 进入http://127.0.0.1:8000/admin/bookstore/book/ 查看显示方式和以前有所不同
- 在
模型管理器类ModelAdmin中实现的高级管理功能
- list_display 去控制哪些字段会显示在Admin 的修改列表页面中。
- list_display_links 可以控制list_display中的字段是否应该链接到对象的“更改”页面。
- list_filter 设置激活Admin 修改列表页面右侧栏中的过滤器
- search_fields 设置启用Admin 更改列表页面上的搜索框。
- list_editable 设置为模型上的字段名称列表,这将允许在更改列表页面上进行编辑。
- 其它参见https://docs.djangoproject.com/en/2.2/ref/contrib/admin/
再谈Meta类
通过Meta内嵌类 定义模型类的属性
- 模型类可以通过定义内部类class Meta 来重新定义当前模型类和数据表的一些属性信息
- 用法格式如下:
1
2
3
4
5
6
7
8
9class Book(models.Model):
title = CharField(....)
class Meta:
1. db_table = '数据表名'
- 该模型所用的数据表的名称。(设置完成后需要立马更新同步数据库)
2. verbose_name = '单数名'
- 给模型对象的一个易于理解的名称(单数),用于显示在/admin管理界面中
3. verbose_name_plural = '复数名'
- 该对象复数形式的名称(复数),用于显示在/admin管理界面中
数据表关联关系映射
- 常用的表关联方式有三种:
- 一对一映射
- 如: 一个身份证对应一个人
- 一对多映射
- 如: 一个班级可以有多个学生
- 多对多映射
- 如: 一个学生可以报多个课程,一个课程可以有多个学生学习
- 一对一映射
一对一映射
- 一对一是表示现实事物间存在的一对一的对应关系。
- 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
语法
1 | class A(model.Model): |
外键类字段选项
特殊字段参数【必须项】:
- on_delete
- models.CASCADE 级联删除。 Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象。
- models.PROTECT 抛出ProtectedError 以阻止被引用对象的删除;[等同于mysql默认的RESTRICT]
- models.SET_NULL 设置ForeignKey null;需要指定null=True
- models.SET_DEFAULT 将ForeignKey设置为其默认值;必须设置ForeignKey的默认值。
- … 其它参请参考文档 https://docs.djangoproject.com/en/2.2/ref/models/fields/#foreignkey
- on_delete
其余常用的字段选项【非必须项】;如:
- null
- unique 等
用法示例
- 创建作家和作家妻子类
1
2
3
4
5
6
7
8
9
10
11# file : xxxxxxxx/models.py
from django.db import models
class Author(models.Model):
'''作家模型类'''
name = models.CharField('作家', max_length=50)
class Wife(models.Model):
'''作家妻子模型类'''
name = models.CharField("妻子", max_length=50)
author = models.OneToOneField(Author, on_delete=models.CASCADE) # 增加一对一属性 - 创建一对一的数据记录
1
2
3
4from .models import *
author1 = Author.objects.create(name='王老师')
wife1 = Wife.objects.create(name='王夫人', author=author1) # 关联王老师
author2 = Author.objects.create(name='小泽老师') # 一对一可以没有数据对应的数据 - 数据查询
正向查询
- 直接通过关联属性查询即可
1
2
3
4# 通过 wife 找 author
from .models import Wife
wife = Wife.objects.get(name='王夫人')
print(wife.name, '的老公是', wife.author.name)
- 直接通过关联属性查询即可
反向查询
- 通过反向关联属性查询
- 反向关联属性为
实例对象.引用类名(小写)
,如作家的反向引用为作家对象.wife
- 当反向引用不存在时,则会触发异常
1
2
3
4
5
6
7
8# 通过 author.wife 关联属性 找 wife,如果没有对应的wife则触发异常
author1 = Author.objects.get(name='王老师')
print(author1.name, '的妻子是', author1.wife.name)
author2 = Author.objects.get(name='小泽老师')
try:
print(author2.name, '的妻子是', author2.wife.name)
except:
print(author2.name, '还没有妻子')
一对多映射
- 一对多是表示现实事物间存在的一对多的对应关系。
- 如:一个学校有多个班级,一个班级有多个学生, 一本图书只能属于一个出版社,一个出版社允许出版多本图书
语法
- 当一个A类对象可以关联多个B类对象时
1
2
3
4
5class A(model.Model):
...
class B(model.Model):
属性 = models.ForeignKey("一"的模型类, on_delete=xx)
- 当一个A类对象可以关联多个B类对象时
用法示例
- 有二个出版社对应五本书的情况.
清华大学出版社
有书- C++
- Java
- Python
北京大学出版社
有书- 西游记
- 水浒
- 有二个出版社对应五本书的情况.
创建模型类
1
2
3
4
5
6
7
8
9
10
11
12# file: otm/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 = ForeignKey(Publisher, on_delete=models.CASCADE)
创建数据
1
2
3
4
5
6
7
8
9#先创建 '一' ,再创建 '多'
from .models import *
pub1 = Publisher.objects.create(name='清华大学出版社')
Book.objects.create(title='C++', publisher=pub1)
Book.objects.create(title='Java', publisher_id=1)
#高级创建 - 利用 反向属性
pub2 = Publisher.objects.create(name='北京大学出版社')
pub2.book_set.create(title='西游记')数据查询
通过 Book 查询 Publisher【正向】
1
2
3
4
5通过 publisher 属性查询即可
book.publisher
abook = Book.objects.get(id=1)
print(abook.title, '的出版社是:', abook.publisher.name)通过 Publisher 查询 对应的所有的 Book 【反向】
1
2
3
4
5
6
7
8
9
10Django会在Publisher中增加一个属性来表示对对应的Book们的查询引用
属性:book_set 等价于 objects
# 通过出版社查询对应的书
pub1 = Publisher.objects.get(name='清华大学出版社')
books = pub1.book_set.all() # 通过book_set 获取pub1对应的多个Book数据对象
#books = Book.objects.filter(publisher=pub1) # 也可以采用此方式获取
print("清华大学出版社的书有:")
for book in books:
print(book.title)
多对多映射
- 多对多表达对象之间多对多复杂关系,如: 每个人都有不同的学校(小学,初中,高中,…),每个学校都有不同的学生…
语法
- 在关联的两个类中的任意一个类中,增加:
1
属性 = models.ManyToManyField(MyModel)
- 在关联的两个类中的任意一个类中,增加:
用法示例
- 一个作者可以出版多本图书
- 一本图书可以被多名作者同时编写
1
2
3
4
5
6class Author(models.Model):
...
class Book(models.Model):
...
authors = models.ManyToManyField(Author)
创建模型类
1
2
3
4
5
6
7
8
9
10
11
12class 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)
authors = models.ManyToManyField(Author)
def __str__(self):
return self.title创建数据
1
2
3
4
5
6
7
8
9
10
11
12方案1 先创建 author 再关联 book
author1 = Author.objects.create(name='吕老师')
author2 = Author.objects.create(name='王老师')
# 吕老师和王老师同时写了一本Python
book11 = author1.book_set.create(title="Python")
author2.book_set.add(book11)
方案2 先创建 book 再关联 author
book = Book.objects.create(title='python1')
#郭小闹和吕老师都参与了 python1 的 创作
author3 = book.authors.create(name='guoxiaonao')
book.authors.add(author1)数据查询
- 通过 Book 查询对应的所有的 Author【正向】
1
2book.authors.all() -> 获取 book 对应的所有的author的信息
book.authors.filter(age__gt=80) -> 获取book对应的作者中年龄大于80岁的作者的信息- 通过 Author 查询对应的所有的Book【反向】
- Django会生成一个反向属性 book_set 用于表示对对应的book的查询对象相关操作
1
2author.book_set.all()
author.book_set.filter()