内容导航
- django路由层
内容详细
django路由层
1.路由匹配
django2.X及以上 path第一个参数些什么就匹配什么
django1.X第一个参数是正则表达式
无论匹配什么版本django都自带加斜杠后缀的功能 也可以取消
配置文件中APPEND_SLASH = False 取消加斜杠后缀
2.转换器
正常情况下很多网站都会有很多相似的网址 如果我们每一个都单独开设路由不太合理 django2.X及以上版本路由动态匹配有转换器(五种):
str:匹配除路径分隔符外的任何非空字符串。
int:匹配0或任何正整数。
slug:匹配任意一个由字母或数字组成的字符串。
uuid:匹配格式化后的UUID。
path:能够匹配完整的URL路径
ps:还支持自定义转换器(自己写正则表达式匹配更加细化的内容)
# 转换器 将对应位置匹配刀的数据转换成固定的数据类型
path('index/<str:info>/', views.index_func)
#index_func(实参request对象,info='转换器匹配刀的类型转换之后的内容')
path('index/<>str:info/<int:id>/', views.index_func)
#index_func(实参request对象,info='转换器匹配刀的类型转换之后的内容',id='转换器匹配刀的类型转换之后的内容')
3.正则匹配
django2.X及以上版本又re_path 第一个参数是正则
匹配的本质是只要第一个正则表达式能够从用户输入的路由中匹配到数据就算匹配成功会立刻停止路由层其他的匹配直接执行对应的视图函数
re_path('^test/$', views.test)
django1.x路由匹配使用的是url() 功能与django2.x及以上的re_path()一致
4.正则匹配的无名有名分组
无名分组
re_path('^test/(\d{4})/', views.test)
会将括号内正则匹配到的内容当做位置参数传递给视图函数
有名分组
re_path('^test/(?P<year>\d{4})', views.test)
会将括号内正则匹配到的内容当作关键字参数传递给视图函数
# 注意上述分组不能混合使用!!!
5.反向解析
通过一个名字可以反向解析出一个结果 该结果可以访问到某个对应的路由
基本使用
1.路由匹配关系起别名
path('login001/', views.login, name='login_view')
2.反向解析语法
html页面上模板语法 {% url 'login_view' %}
后端语法 reverse('login_view') # reverse需要导模块
动态路由的反向解析
path('func1/<str:others>', views.func1_func, name='func1_view')
html页面上反向语法{% url 'func1_view' 'jason' %}
后端语法 reverse('func1_view', args=('嘿嘿嘿',))
6.路由分发
django支持每个应用都可以有自己独立的路由层、静态文件、模板层。基于该特性多人开发项目就可以完全解耦合,之后利用路由分发还可以整合到一起
多个应用都有很多路由与视图函数的对应关系 这个时候可以拆分到各自的路由层中
使用路由分发之前 总路由直接干路由与视图函数的匹配的活
path('index/',index)
使用路由分发之后 总路由只按照应用名分配匹配方向
path('app01/', include('app01.urls'))
'''应用文件内创建urls.py为子路由的路由层'''
7.名称空间
路由分发之后 针对相同的别名能否自动反向解析出不同的应用前缀
默认情况下是无法直接识别应用前缀的
如果想要正常识别区分有两种方式:
方式1:名称空间
总路由
path('app01/', include(('app01.urls','app01'), namespace='app01')),
path('app02/', include(('app02.urls', 'app02'), namespace='app02')),
反向解析
reverse('app01:index_view')
reverse('app01:index_view')
方式2:别名不冲突即可 # 推荐使用
多个应用别名不冲突可以用应用名作为别名的前缀
path('index/',view.index, name='app01_index_view')
path('index/',view.index, name='app02_index_view')
8.虚拟环境
项目1需要使用:django1.11 python38
项目2需要使用:django2.22 pymysql requests python38
项目3需要使用:django3.22 request_html flask urllib3 python38
实际开发项目中我们只会给项目配备所需的环境,不需要的一概不配!!!
虚拟环境:能够针对相同版本的解释器创建多个分身 每个分身可以有自己独立的环境
pycharm创建虚拟环境:(每创建一个虚拟环境就相当于重新下载了一个全新的解释器)
命令行的方式: python -m venv pyvenv38
注意:python命令此处不支持多版本共存的操作 python27 python36 python38
激活
activate
关闭
deactivate
pip install --index-url http://mirrors.aliyun.com/pypi/simple/ django==1.11.11 --trusted-host mirrors.aliyun.com
django视图层
1.视图层之必会三板斧
用来处理请求的视图函数都必须返回HttpResponse对象
class HttpResponse:
pass
return HttpResponse()
def render():
return HttpResponse()
return render()
def redirect():
redirect_class = 类(祖先有个类是HttpResponse)
return redirect_class()
return redirect()
2.JsonResponse对象
from django.http import JsonResponse
def index_func(request):
return HttpResponse('嘿嘿嘿')
返回给浏览器一个json格式的字符串
user_dict = {'name':'jason老师','age':18}
1.第一种方式
import json
user_json = json.dumps(user_dict, ensure_ascii=False)
return HttpResponse(user_json)
2.第二种方式
return JsonResponse(user_dict)
#如果像阻止转码 需要添加参数
return JsonResponse(user_dict, json_dumps_params={'ensure_ascii: False'})
ps: 以后写代码很多时候可能需要参考源码及所学知识扩展功能
class JsonResponse():
def __init__(self,data,json_dumps_params=None):
json.dumps(data,**json_dunps_params)
JsonResponse主要序列化字典 针对非字典的其他可以被序列化的数据需要修改safe参数为False
3.request对象获取文件
form表单携带文件类型的数据需要做到以下几点
1.method必须是post
2.enctype必须是multipart/form-data
django后端需要通过request.FILES获取文件类型的数据
4.视图层之FBV与CBV
FBV
基于函数的视图
def index(request):return HttpResponse对象
CBV
基于类的视图
from django import views
class MyLoginView(views.View): # 必须要添加views.View参数
def get(self, request):
return HttpResponse('from CBV get function')
def post(self, request):
return HttpResponse('from CBV post function')
urls文件中:path('login/', views.MyLoginView.as_view())
5.CBV源码剖析(重要)
1.从CBV的路由匹配切入
path('login/', views.MyLoginView.as_view())
1.类名点名字(名字的查找问题)
2.类名点名字并加括号调用(静态方法、绑定给类的方法)
2.函数名加括号执行优先级最高 项目已启动就会自动执行as_view
path('login/',views.view) # CBV路由本质还是FBV
3.浏览器地址栏访问login路由需要执行view函数
1.产生我们自己编写的类的对象
2.对象调用dispatch方法(注意查找顺序)
4.研究父类中的dispatch方法
获取当前请求方法并转小写 之后利用反射获取类中对应的方法并执行
class View:
@classmethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
return self.dispatch(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
handler = getattr(self, request.method.lower())
return handler(request, *args, **kwargs)
django模板层
1.模板语法传值
"""
{{}}: 主要与数据值相关
{%%}: 主要与逻辑相关
django的模板语法是自己写的 跟jinja2不一样
1.针对需要加括号调用的名字 django模板语法会自动加括号调用你只需要写名字就行
2.模板语法的注释前端浏览器是无法查看的{##}
"""
1.模板语法传值
return render(request, 'demo02.html', {'n1': name, 'a1':age})
# 传值方式1:精准传值 不浪费资源 针对多资源的传递书写麻烦
return render(request, 'demo02.html', locals()) # 传值方式2:将函数名称空间中的所有的名字全部传递 名字过多并且不使用的情况下比较浪费资源
2.模板语法传值特性
1.基本数据类型正常展示
2.文件对象也可以展示并调用方法
3.函数名会自动加括号执行并将返回值展示到页面上(不支持额外传参)
4.类名也会自动加括号调用
5.对象则不会
ps:总结针对可以加括号调用的名字模板语法都会自动加括号调用
3.模板语法之过滤器(内置函数)
{{i|add:10}} |add: # 自增
{{l|length}} |length # 长度
{{s|slice:'1:4'}} |slice:'' # 切割
{{s|truncatechars:5}} |truncatechars: # 按字符数显示 剩下的用... ...占用一个字符数
{{s|truncatewords:1}} |truncatewords: # 按单词数显示 剩下的用...
{{ctime|date:'Y年-m月-d日 H:i:s'}} # 后端导入datetime.today()模块 html文件中模板语法写入时间模块
{{file_size|filesizeformat }} # 按合适的单位展示字节数大小
{{h1|safe}} # 后端使用前端语法代码传输html模板语法中直接可以执行c前端代码
2.模板层之标签
{% if 条件1(可以自己写也可以用传递过来的数据) %}
<p>今天又是周三</p>
{% elif条件2(可以自己写也可以用传递过来的数据) %}
<p>百日冲刺</p>
{% else %}
<p>没多少时间了!</p>
{% endif %}
{% for k in t1 %}
{% if forloop.first %}
<p>这是我的第一次循环{{ k }}</p>
{% elif forloop.last %}
<p>这是我的最后一次循环{{ k }}</p>
{% else %}
<p>这是中间循环{{ k }}</p>
{% endif %}
{% empty %}
<p>你给我传的数据是空的无法循环取值(空字符串、空列表、空字典)</p>
{% endfor %}
django模板语法取值操作>>>:只支持句点符
句点符既可以点索引也可以点键
{{ d1.hobby.2.a1 }}
{% with d1.hobby.2.a1 as h %} 复杂数据获取之后需要反复使用可以起别名
<a href="">{{ h }}</a>
{% endwith %}
3.自定义过滤器、标签及inclusion_tag(了解)
"""
如果想要自定义一些模板语法 需要先完成下列的三步走战列
1.在应用下创建一个名字必须叫templatetags的目录
2.在上述目录下创建任意名称的py文件
3.在上述py文件内先编写两行固定的代码
from django import template
register = template.Library()
"""
# templatetags目录下自定义文件中
# 自定义过滤器(最大只能接收两个参数)
@register.filter(name='myadd')
def func1(a, b):
rerurn a + b
# html文件中
{% load mytags %}
<p>{{ i|myadd:1 }}</p>
#自定义标签(参数没有限制)
@register.simple_tag(name'mytag')
def func2(a, b, c, d, e):
return f'{a}-{b}-{c}-{d}-{e}'
{% load mytags %}
{% mytag 'jason' 'kevin' 'oscar' 'tony' 'lili' %} # 空格隔开即可
# 自定义inclusion_tag(局部的html代码)
@register.inclusion_tag('menu.html', name='mymenu') # menu.html写内容
def func3(n):
html = []
for i in range(n):
html.append('<li>第%s页</l1>'%i)
return locals()
{% load mytags %} # 指定文件内写模板语法调用
{% mymenu 20 %}
4.母版的继承与导入
母版的继承(重要)
多个页面有很多相似的地方 我们可以采取下列方式
方式1:传统的复制粘贴
方式2:母版的继承
1.在母版中使用block划定子板后可以修改的区域
{% block 区域名称 %}
{% endblock %}
2.子版继承母版
{% extends 'home.html' %}
{% block 区域名称 %}
子板自己的内容
{% endblock %}
ps:母版中至少应该有三个区域
页面内容区、css样式区、js代码区
补充:子板也可以继续使用母版的内容
{{ block.super }}
母版的导入(了解)
将某个html的部分提前写好 之后很多html页面都相适应就可以导入
{% include 'myform.html' %}
django模型层
1.模型层之前期准备
1.自带的sqlite3数据库对事件字段不敏感 有时候会展示错乱 所以我们习惯切换成常见的数据库比如MySQL django orm并不会自动帮你创建库 所以需要提前准备好
2.单独测试django某个功能层
默认不允许单独测试某个py文件 如果想要测试某个py文件(主要是models.py)
测试环境1:pycharm提供的python console
测试环境2:自己搭建(自带的test或者自己创建)
1.拷贝manage.py前四行
2.自己再加两行
import django
django.setup()
# 测试信息写在函数内
3.django ORM底层还是SQL语句 我们是可以查看的
如果我们手上是一个QuerySet对象 那么可以直接点query查看SQL语句
# res = models.User.object.file()
# print(res.query)
如果想查看所有ORM底层的SQL语句也可以在配置文件添加日志记录
在settings.py中添加以下代码
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
2.ORM常用关键字
1.create() 创建数据并直接获取当前创建的数据对象
res = models.User.objects.create(name='guts',age=22)
print(res) # 返回的是创建的数据对象
2.filter() 根据条件筛选数据 结果是QuerySet [数据对象1,数据对象2]
res = models.User.objects.filter() # 查看全部
res = models.User.objects.filter(name='guts') # 查看指定字段
res = models.User.objects.filter(name='guts',age=22) # and连接
3.first() last() QuerySet支持索引取值但是只支持正数 并且ORM不建议你使用索引
res = models.User.objects.filter()[1] # 数据不存在索引取值会报错
res = models.User.objects.filter(pk=100).first() # 数据不存在不会报错而是返回None
res = models.User.objects.filter(pk=100).last() # 数据不存在不会报错而是返回None
4.update() 更新数据(批量更新)
models.User.objects.filter().update() # 全部更新
models.User.objects.filter(id=1),update() # 单个更新
5.delete() 删除数据(批量删除)
models.User.objects.filter().delete() # 批量删除
models.User.objects.filter(id=1).delete() # 单个删除
6.all() 查询所有数据 结果是QuerySet [数据对象1,数据对象2]
res = models.User.object.all()
7.values() 根据指定字段获取数据 结果是QuerySet [{},{},{}]
res = models.User.objects.all().values('name')
res = models.User.objects.filter().values()
res = models.User.objects.values()
8.values_list() 根据指定字段获取数据 结果是QuerySet [(),(),()]
res = models.User.objects.all().values_list('name','age')
9.distinct() 去重 数据一定要一模一样才可以 如果有主键肯定不行
res = models.User.objects.values('name','age').distinct()
10.order_by() 根据指定条件排序 默认是升序 字段前面加符号就算降序
res = models.User.objects.all().order_by('age')
print(res)
11.get() 根据条件筛选数据并直接获取到数据对象 一旦条件不存在会直接报错
不建议使用
res = models.User.objects.get(pk=1)
print(res)
res = models.User.objects.get(pk=100,name='guts') # 直接报错
12.exclude() 取反操作
res = models.User.object.exclude(pk=1)
print(res)
13.reverse() 颠倒顺序(被操作的对象必须是已经排过序的才可以)
res = models.User.object.all()
res = models.User.object.all().order_by('age')
res1 = models.User.object.all().order_by('age').reverse()
print(res, res1)
14.count() 统计结果集中数据的个数
res = models.User.objects.all().count()
print(res)
15.exists() 判断结果集中是否含有数据 如果有则返回True 没有则返回False
res = models.User.objects.all().exists()
print(res)
res1 = models.User.objects.filter(pk=100).exists()
print(res1)
3.ORM执行SQL语句
有时候ORM的操作效率可能偏低 我们是可以自己编写SQL的
方式1:
models.User.objects.raw('select * from app01_user;')
方式2:
from django.db import connection
cursor = connection.cursor()
cursor.execute('select name from app01_user;')
print(cursor.fetchall())
4.神奇的双下划线查询
"""
只要还是queryset对象就可以无限制的点queryset对象的方法
queryset.filter().values().filter().values_list().filter()...
"""
# 查询年龄大于18的用户数据
res = models.User.objects.filter(age__gt=18) # __gt大于
# 查询年龄小于38岁的用户数据
res = models.User.objects.filter(age__lt=38) # __lt小于
# 大于等于 小于等于
res = models.User.objects.filter(age__gte=18) # __gte大于等于
res = models.User.objects.filter(age__lte=30) # __lte小于等于
# 查询年龄是18或者28或者38的数据
res = models.User.objects.filter(age__in=(18,28,38))
# 查询年龄在18到38范围之内的数据
res = models.User.objects.filter(age__range=(18,38))
# 查询名字中含有字母j的数据
res = models.User.objects.filter(name__contains='j') # 区分大小写
res = models.User.objects.filter(name__icontains='j') # 不分大小写
# 查询注册年份是2022的数据
res = models.User.objects.filter(register_time__year=2022)
'''针对django框架的时区问题 是需要配置文件中修改的 后续bbs讲解'''
5.ORM外键字段的创建
'''
复习MySQL外键关系
一对多
外键字段建在多的一方
多对多
外键字段建在第三张关系表
一对一
建在任何一方都可以 但是建议建在查询频率较高的表中
ps:关系的判断可以采用换位思考原则 熟练了之后可以瞬间判断
'''
1.创建基础表(书籍表、出版社表、作者表、作者详情)
2.确定外键关系
一对多 ORM与MySQL一致 外键字段建在多的一方
多对多 ORM比MySQL有更多变化
1.外键字段可以直接建在某张表中(查询频率较高的)
内部会自动帮你创建第三张表关系
2.自己创建第三张表关系并创建外键字段
详情后续讲解
一对一 ORM与MySQL一致 外键字段建在查询频率较高的一方
3.ORM创建
针对一对多和一对一同步到表中之后会自动加_id的后缀
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
author_detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)
针对多对多 不会在表中有展示 而是创建第三张表
authors = models.ManyToManyField(to='Author')
6.外键字段相关操作
# 针对一对多 插入数据可以直接填写表中的实际字段
models.Book.objects.create(title='三国演义',price=888.88,publish_id=1)
models.Book.objects.create(title='人性的弱点',price=777.77,publish_id=1)
# 针对一对多 插入数据也可以填写表中的类中字段名
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.create(title='水浒传',price=555.66,publish=publish_obj)
'''一对一与一对多 一致'''
既可以传数字也可以传对象
# 针对多对多关系绑定
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1) # 在第三章关系表中给哦当前书籍绑定作者
book_obj.authors.add(2,3)
book_obj = models.Book.objects.filter(pk=4).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj1)
book_obj.authors.add(author_obj1,author_obj2)
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set((1,3)) # 修改关系
book_obj.authors.set([2,]) # 修改关系
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.authors.set((author_obj1,))
book_obj.authors.set((author_obj1,author_obj2))
book_obj.authors.remove(2) # 删除数据
book_obj.authors.remove(author_obj1,author_obj2)
book_obj.authors.clear() # 清空
add()\remove() 多个位置参数(数字 对象)
set() 可迭代对象(元组 列表) 数字 对象
clear() 清空当前数据对象的关系
7.ORM跨表查询
"""
复习MySQL跨表查询的思路
子查询
分步操作:将一条SQL语句用括号括起来当作另一条SQL语句的条件
连表操作
先整合多张表之后基于单表查询即可
inner join 内连接
left join 左连接
right join 右连接
"""
正反向查询的概念(重要)
正向查询
由外键字段所在的表数据查询关联的表数据 正向
反向查询
没有外键字段的表数据查询关联的表数据 反向
ps:正反向的核心就是看外键字段在不在当前数据所在的表中
ORM跨表查询的口诀(重要)
正向查询按外键字段
反向查询按表名小写
8.基于对象的跨表查询
# 1.查询主键为1的书籍对应的出版社名称
# 先根据条件获取数据对象
# book_obj = models.Book.objects.filter(pk=1).first()
# 再判断正反向的概念 由书查出版社 外键字段在书所在的表中 所以是正向查询
# print(book_obj.publish.name)
# 2.查询主键为4的书籍对应的作者姓名
# 先根据条件获取数据对象
# book_obj = models.Book.objects.filter(pk=4).first()
# 再判断正反向的概念 由书查作者 外键字段在书所在的表中 所以是正向查询
# print(book_obj.authors) # app01.Author.None
# print(book_obj.authors.all())
# print(book_obj.authors.all().values('name'))
# 3.查询jason的电话号码
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail.phone)
# 4.查询北方出版社出版过的书籍
# publish_obj = models.Publish.objects.filter(name='北方出版社').first()
# print(publish_obj.book_set) # app01.Book.None
# print(publish_obj.book_set.all())
# 5.查询jason写过的书籍
# author_obj = models.Author.objects.filter(name='jason').first()
# print(author_obj.book_set) # app01.Book.None
# print(author_obj.book_set.all())
# 6.查询电话号码是110的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
print(author_detail_obj.author)
print(author_detail_obj.author.name)
9.基于上下划线的跨表查询
'''基于双下划线的跨表查询'''
# 1.查询主键为1的书籍对应的出版社名称
# res = models.Book.objects.filter(pk=1).values('publish__name','title')
# print(res)
# 2.查询主键为4的书籍对应的作者姓名
# res = models.Book.objects.filter(pk=4).values('title', 'authors__name')
# print(res)
# 3.查询jason的电话号码
# res = models.Author.objects.filter(name='jason').values('author_detail__phone')
# print(res)
# 4.查询北方出版社出版过的书籍名称和价格
# res = models.Publish.objects.filter(name='北方出版社').values('book__title','book__price','name')
# print(res)
# 5.查询jason写过的书籍名称
# res = models.Author.objects.filter(name='jason').values('book__title', 'name')
# print(res)
# 6.查询电话号码是110的作者姓名
res = models.AuthorDetail.objects.filter(phone=110).values('phone', 'author__name')
print(res)
10.进阶操作
# 1.查询主键为1的书籍对应的出版社名称
# res = models.Publish.objects.filter(book__pk=1).values('name')
# print(res)
# 2.查询主键为4的书籍对应的作者姓名
# res = models.Author.objects.filter(book__pk=4).values('name','book__title')
# print(res)
# 3.查询jason的电话号码
# res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
# print(res)
# 4.查询北方出版社出版过的书籍名称和价格
# res = models.Book.objects.filter(publish__name='北方出版社').values('title','price')
# print(res)
# 5.查询jason写过的书籍名称
# res = models.Book.objects.filter(authors__name='jason').values('title')
# print(res)
# 6.查询电话号码是110的作者姓名
res = models.Author.objects.filter(author_detail__phone=110).values('name')
print(res)
"""
补充
# 查询主键为4的书籍对应的作者的电话号码
# res = models.Book.objects.filter(pk=4).values('authors__author_detail__phone')
# print(res)
# res = models.AuthorDetail.objects.filter(author__book__pk=4).values('phone')
# print(res)
res = models.Author.objects.filter(book__pk=4).values('author_detail__phone')
print(res)
"""
11.聚合查询
聚合函数:Max Min Sum Count Avg
在ORM中支持单独使用聚合函数 aggregate
from django.db.models import Max, Min, Sum, Count, Avg
res = models.Book.objects.aggregate(Max('price'), Count('pk'),最小价格=Min('price'), allPrice=Sum('price'),平均价格=Avg('price'))
print(res)
12.分组查询
"""
如果执行orm分组查询报错 并且有关键字sql_mode strict mode
移除sql_mode中的only_full_group_by
"""
# 分组查询
# 统计每一本书的作者个数
# res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')
# print(res)
# 统计出每个出版社卖的最便宜的书的价格
# res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
# print(res)
# 统计不止一个作者的图书
# 1.先统计每本书的作者个数
# res = models.Book.objects.annotate(author_num=Count('authors__pk'))
# 2.筛选出作者个数大于1的数据
# res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title',
# 'author_num')
# print(res)
# 查询每个作者出的书的总价格
# res = models.Author.objects.annotate(总价=Sum('book__price'),count_book=Count('book__pk')).values('name','总价','count_book')
# print(res)
"""
models.表名.objects.annotate() 按照表分组
models.表名.objects.values('字段名').annotate() 按照values括号内指定的字段分组
"""
res = models.Book.objects.values('publish_id').annotate(count_pk=Count('pk')).values('publish_id', 'count_pk')
print(res)
13.F与Q查询
# 1.查询库存数大于卖出数的书籍
'''当查询条件不是明确的 也需要从数据库中获取 就需要使用F查询'''
from django.db.models import F
# res = models.Book.objects.filter(kucun__gt=F('maichu'))
# print(res)
# 2.将所有书的价格涨800
# models.Book.objects.update(price=F('price') + 800)
# 3.将所有书的名称后面追加爆款
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'), Value('新款')))
# 查询主键是1或者价格大于2000的书籍
# res = models.Book.objects.filter(pk=1, price__gt=2000) # 逗号默认是and关系
from django.db.models import Q
# res = models.Book.objects.filter(Q(pk=1), Q(price__gt=2000)) # 逗号是and
# res = models.Book.objects.filter(Q(pk=1) | Q(price__gt=2000)) # |是or
res = models.Book.objects.filter(~Q(pk=1) | Q(price__gt=2000)) # ~是not
print(res.query)
标签:总结,__,models,res,django,filter,objects,print
From: https://www.cnblogs.com/DragonY/p/16990738.html