一、例表结构
- 正向跨表:指显式或隐式通过外键,从外键所在的表到外键指向的表
- 反向跨表:指显式或隐式通过外键,从外键指向的表到外键所在的表
二、返回数据类型
2.1 单object对象
代表函数:first,last
功能:返回一个object对象,即代表一行,点运算符可获得具体数据
-
写法
名称 写法 返回 本表操作 res = models.Stu.objects.first()
res为 Stu object (1)
,表Stu的第一行正向跨表 res = models.Stu.objects.first().stu_detail
res为 StuDetail object (2)
,表StuDetail的第二行反向跨表 res = models.Publish.objects.first().book_set
res为 api.Book.None
,效果等同于model.Book.objects
2.2 obj列表式QuerySet对象
代表函数:filter,all(性能较低,避免)
功能:返回一个queryset对象,即代表多行的一个列表,点运算符可获得一个object对象
-
写法
名称 写法 返回 本表操作 res = models.Publish.objects.all()
<QuerySet[
<Publish: Publish object (1)>,
<Publish: Publish object (2)>
]>正向跨表 res = models.Stu.objects.filter(stu_detail__height=165.4)
<QuerySet [
<Stu: Stu object (2)>
]>反向跨表 res = models.StuDetail.objects.filter(stu__id=3)
<QuerySet [
<StuDetail: StuDetail object (3)>
]> -
QuerySet–>object–>具体数据
def dblink(request): # 拿到Stu的所有行的QuerySet对象 stu = models.Stu.objects.all() for item in stu: # 正向查询操作:本表项;本表外键项的值;连表:执行跨表取值,stu_detail为Stu的外键 print(item.name, item.stu_detail_id, item.stu_detail.height) # 反向查询操作 # 首先取Publish表中第二项的object对象 obj = models.Publish.objects.last() print('出版社:', obj.name) # 然后obj.外键所在表小写_set.all(),返回Book表的QuerySet对象 res = obj.book_set.all() for row in res: print('包含科目:', row.name) return HttpResponse('操作dblink结束')
-
显示
2.3 字典列表式QuerySet对象
代表函数:values
功能:返回一个字典列表的QuerySet对象
-
写法
名称 写法 返回 本表操作 res = models.Stu.objects.values('id', 'name')
<QuerySet [
{‘id’: 1, ‘name’: ‘sam’},
{‘id’: 2, ‘name’: ‘duke’},
{‘id’: 3, ‘name’: ‘jane’}
]>正向跨表 res = models.Stu.objects.values('id', 'stu_detail__gender')
<QuerySet [
{‘id’: 2, ‘stu_detail__gender’: 1},
{‘id’: 1, ‘stu_detail__gender’: 2},
{‘id’: 3, ‘stu_detail__gender’:0}
]>反向跨表 res = models.StuDetail.objects.values('id', 'stu__name')
<QuerySet [
{‘id’: 1, ‘stu__name’: ‘duke’},
{‘id’: 2, ‘stu__name’: ‘sam’},
{‘id’: 3, ‘stu__name’: ‘jane’}
]> -
数据取法
def dblink(request): res = models.StuDetail.objects.values('id', 'stu__name') # 仅写stu等同于stu__id print(res) for item in res: print(item['id'], item['stu__name']) return HttpResponse('操作结束')
-
显示
<QuerySet [{'id': 1, 'stu__name': 'duke'}, {'id': 2, 'stu__name': 'sam'}, {'id': 3, 'stu__name': 'jane'}]> 1 duke 2 sam 3 jane
2.4 元组列表式QuerySet对象
代表函数:values_list
功能:返回一个元组列表式QuerySet对象
-
写法
名称 写法 返回 本表操作 res = models.Stu.objects.values_list('id', 'name')
<QuerySet [(1, ‘sam’), (2, ‘duke’), (3, ‘jane’)]> 正向跨表 res = models.Stu.objects.values_list('id', 'stu_detail__gender')
<QuerySet [(2, 1), (1, 2), (3, 0)]> 反向跨表 res = models.StuDetail.objects.values_list('id', 'stu__name')
<QuerySet [(1, ‘duke’), (2, ‘sam’), (3, ‘jane’)]> -
数据取法
def dblink(request): res = models.StuDetail.objects.values_list('id', 'stu__name') print(res) for item in res: print(item[0],item[1]) return HttpResponse('操作结束')
-
显示
<QuerySet [(1, 'duke'), (2, 'sam'), (3, 'jane')]> 1 duke 2 sam 3 jane
三、常规函数
3.1 create函数
3.1.1 create函数
- 常规写法:
models.Stu.objects.create(name='sam', stu_detail_id=2)
- 进阶写法:
- 写法:
obj = models.Stu.objects.create(name='sam', stu_detail_id=2)
- 意义:obj代表这一行,创建后取得这行的object对象
- 写法:
- 字典写法:
def dblink(request): # name_list可以写成[{},{},]形式,配合for循环 name_list = {'id': '3', 'name': 'publish_test'} res = models.Publish.objects.create(**name_list) print(res) return HttpResponse('<h1>处理结束</h1>')
3.1.2 bulk_create函数
- 功能:批量生成,并控制每次任务量
- 写法
def dblink(request): obj_list = { models.Publish(id=3, name='publish_1'), # 此语句在内存中生成一个publish的object对象 models.Publish(id=4, name='publish_2'), models.Publish(id=5, name='publish_3'), } # 字典,数据库中每次创建记录的最大个数 res = models.Publish.objects.bulk_create(obj_list, 2) print(res) # [<Publish: Publish object (3)>, <Publish: Publish object (4)>, <Publish: Publish object (5)>] return HttpResponse('<h1>处理结束</h1>')
3.1.3 get_or_create函数
- 功能:检测符合条件行是否存在,存在返回,不存在则新建
- 写法
def dblink(request): # obj:存在接收返回的object,不存在接收新增的object # exit_y:判断是否为新建的object,布尔值 obj, exit_y = models.StuDetail.objects.get_or_create( height=166.4, # 筛选条件一 gender=2, # 筛选条件二 defaults={'birthday': '1987-6-6'} # 若不存在,需在此填写值notnull的各列 ) print(obj, exit_y) return HttpResponse('<h1>处理结束</h1>')
注意:若检测有多个符合条件,则报错
措施:去重distinct,或者加try语句
3.1.4 update_or_create函数
- 功能:检测符合条件行是否存在,存在更新,不存在则新建
- 写法:同3.1.3
3.2 all函数
- 常规用法
def dblink(request): res = models.Stu.objects.all() # 性能优化只针对这一行 for item in res: print(item.name, item.stu_detail.height) # 连表导致性能下降 return HttpResponse('<h1>处理结束</h1>')
- 性能优化(针对外键连表):
- select_related
- 触发情境:数据量小,参数为外键
- 写法:
res = models.Stu.objects.all().select_related('stu_detail')
- prefetch_related
- 触发情境:数据量庞大,参数为外键
- 写法:
res = models.Stu.objects.all().prefetch_related('stu_detail')
- select_related
四、filter函数
- 筛选
- 包含:
models.Stu.objects.filter(见3.1)
- 不包含:
models.Stu.objects.exclude(同filter)
- 包含:
4.1 条件筛选
-
数字比较
写法 意义 写法 意义 __gt 大于 __gte 大于等于 __lt 小于 __lte 小于等于 __range 在什么区间内 __in 存在于一个list范围内 写法:
- 数字:
models.Stu.objects.filter(id__lte=2)
,id≤2的queryset - 区间:
models.Stu.objects.filter(id__range=[2,3])
,id只能取2~3,包含2,3的queryset - 范围:
models.Stu.objects.filter(id__in=[1,3])
,id只能取1、3的queryset
- 数字:
-
字符筛选
写法 意义 写法 意义 __startswith 以什么字符开始 __istartswith 以什么字符开始,忽略大小写 __endswith 以什么字符开始 __iendswith 以什么字符开始,忽略大小写 __contains 包含字符 __icontains 包含字符,忽略大小写 写法:
models.Book.objects.filter(name__startswith='mat').first()
,选择以‘mat’开头的object -
日期筛选
写法 意义 写法 意义 __year 日期字段的年 __month 日期字段的月 __day 日期字段的日 __isnull=True/False 判断是否为空 补充:
写法:models.StuDetail.objects.filter(birthday__day=9).first()
,选择日期的日是9的object
比较写法:res = models.StuDetail.objects.filter(birthday__day__gt=9).first()
4.2 复合写法
- 字典条件:将条件以字典方式写入
- 写法
def dblink(request): # 以下为条件字典写法,默认以and逻辑筛选 con = { 'id__gt': 1, 'height': 180.3, } res = models.StuDetail.objects.filter(**con) print(res) return HttpResponse('<h1>处理结束</h1>')
4.3 Q函数
- 功能:构造复杂的筛选条件
- 简单写法
from django.db.models import Q def dblink(request): # Q 对象可以使用 & | ~ (与 或 非)操作符进行组合 res = models.StuDetail.objects.filter(Q(id__gt=1) & ~Q(height=180.3)) print(res) # 返回:<QuerySet [<StuDetail: StuDetail object (2)>]> return HttpResponse('<h1>处理结束</h1>')
- 前后端交互
from django.shortcuts import HttpResponse from api import models from django.db.models import Q def dblink(request): # 前端构造此字典 con_dict = { # k1、k2、k3之间为or连接,列表中每个数字为and连接 'k1': [1, 2, 3, 4], 'k2': [1, 2], 'k3': [13, 22], } # 构造筛选条件,con( q and q and q ),q内部为or con = Q() # 此处v循环取每一行的列表项 for v in con_dict.values(): # 创建q实例 q = Q() # k1、k2、k3之间为or连接 q.connector = 'OR' # 取出列表中的每个数字 for i in v: # 列表中每个数字为and连接,’id‘也可以为’id__gt‘ q.children.append(('id', i)) # 将q以and逻辑加入到con里 con.add(q, 'AND') # 后端接收字典并进行筛选 res = models.StuDetail.objects.filter(con) print(res) return HttpResponse('<h1>处理结束</h1>')
4.4 F函数
- 功能:在原数据基础上做操作,也可用在filter上
- 写法
from django.db.models import F def dblink(request): # 将本表所有行中height列数据都自加100,也可以先filter再update res = models.StuDetail.objects.update(height=F('height')+100) print(res) # 输出3,为影响到的行数 return HttpResponse('<h1>处理结束</h1>')
五、统计类函数
5.1 聚合查询(aggregate)
- 功能:针对整个表进行统计操作
- 写法
# 导入函数 求总行数,合计,最大值,最小值,平均值 from django.db.models import Count, Sum, Max, Min, Avg def dblink(request): # Count:计算行数,参数若为'id'、'name'、'stu_detail_id'结果相同 res = models.Stu.objects.aggregate(sum_line=Count('name')) print(res) # 返回:{'sum_line': 3},纯字典 return HttpResponse('<h1>处理结束</h1>')
5.2 分组查询(annotate)
- 功能:将某一列相同值进行聚合,即分组,进而使用聚合函数求值
- 写法
# 导入函数 求总行数,合计,最大值,最小值,平均值 from django.db.models import Count, Sum, Max, Min, Avg def dblink(request): # 待统计的表 或values_list 分组依据的列 统计值存放列的别名 res = models.Book.objects.values('publish_id').annotate(sum_line=Count('id')) print(res) # 返回:<QuerySet [{'publish_id': 1, 'sum_line': 1}, {'publish_id': 2, 'sum_line': 2}]> return HttpResponse('<h1>处理结束</h1>')
- filter函数
- 后置:聚合函数处理后过滤,可过滤sum_line列,放在
annotate
函数后 - 前置:分组前过滤,放在
values
函数前
- 后置:聚合函数处理后过滤,可过滤sum_line列,放在
六、函数拾遗
6.1 小众函数
- 去重distinct:
res = models.Book.objects.values('publish_id').distinct()
,配合values、values_list,返回queryset - 排序order_by:
res = models.Stu.objects.all().order_by('id')
- 反序reverse:
res = models.Book.objects.all().order_by('id').reverse()
,需紧跟order_by - 主键筛选in_bulk:
res = models.Book.objects.in_bulk([1,3])
,等价于models.Book.objects.filter(id__in=[1, 3])
- 存在与否exists:
exist_y = models.Book.objects.filter(id=1).exists()
,返回布尔值
6.2 原生sql语句
- extra函数:略
- raw函数:略
- Django翻译后的SQL语句:
print('res.query')