Django请求生命周期
用户在浏览器输入url 发送一个get请求方法的request请求
django中封装了wsgi服务器用来监听端口接受request请求
接收到的请求封装后传入中间件 然后中间件在传入路由分发 再匹配对应的视图函数
视图函数进行业务逻辑处理 然后需要数据相关调用 modles表中对象 通过orm拿到数据库数据,
最后在templates中对应模板进行渲染 渲染好后再传入中间件 通过wsgi再次封装返给浏览器进行展示
路由匹配
在urls.py文件中
1.正则匹配
re_path模块 这样才可以使用正则匹配
re_path('^login/', user_info.views.login),
re_path后面可以直接跟正则表达式 可以用用户输入的路由中进行匹配,只要匹配到了 就会停止对其他 会立即执行对应的视图函数
2.无名分组和有名分组
re_path('^test/(\d+)/', user_info.views.login),
无名分组 通过位置传参 可以传递一个符合(\d+)的参数后端可以接收
re_path('^test/(?P<id>\d+)/', user_info.views.login),
有名分组 通过关键词传参 这里设置的关键词叫id 那后端接收这个传参的时候也要交id,需要和这里辉映 属于给正则起名字 进行关键字传参
path('home/<str:info>', user_info.views.home),
转换器 更加方便 直接接收所有字符串 也是关键字传参方式
反向解析
re_path('^login/<str:id>', user_info.views.login,name='login')
前端
{% url 'login' 123 %}
# 相当于给路由别名为 login对应的函数传递了一个关键字传参 id=123
可以给路由起别名 前端页面可以通过反向解析直接给这个路由函数传参
路由分发
当多个人协同开发 可以有多个app 每个app都可以有自己独自的
urls.py文件 也 自己的templates文件
开发完成后需要全部提交 然后负责人归纳做一个路由分发即可
子路由也就是app内的路由设置 正常设置即可
总路由 根目录下的urls.py文件 为了实现路由分发 需要模块
include模块
from django.urls import path,include,
urlpatterns = [
path('admin/', admin.site.urls),
re_path('^app01/',include('app01.urls')),
re_path('^app02/',include('app02.urls')),
re_path('^app03/',include('app03.urls')),
]
使用正则表达式匹配对应的app文件 然后传入对应的app视图层进行匹配视图函数
名称空间
一个django项目中不可以出现路由别名一样的,这样就会导致名称空间问题
所以当我们路由层起别名时 最好加上app前缀 这样就会导致没有相同的路由别名
确保反向解析没有问题
app01 urls.py
urlpatterns = [ path('login/', views.login, name='app01_login') ]
app02 urls.py
urlpatterns = [path('login/', views.login, name='app02_login')]
前端反向解析:{% url 'app01_login' %} {% url 'app02_login' %}
后端也可以直接重定向
虚拟环境
虚拟环境关键词
venv
在CMD终端创建虚拟环境: python -m venv pyvenv38
虚拟环境:能够针对相同版本的解释器创建多个分身 每个分身可以有自己独立的环境
视图层三板斧
HttpResponse
用来处理请求的视图函数都必须返回HttpResponse对象
返回字符串类型
render
返回html页面 还可以给页面传值
使用字典传值
locals()关键字 传递所有变量名到html页面
return render(request, 'update.html', {name:values} )
return render(request, 'update.html', locals() )
redirect('路由别名')
重定向
jsonResponse对象
前后端交互需要用到json格式
from django.http import JsonResponse
return JsonResponse(user_dict)
return JsonResponse(user_dict)
传送字典可以直接返回
l1 = [11,22,33,44]
return JsonResponse(l1,safe=False)
传送列表需要 safe=False
form如何上传文件/request对象获取文件
form表单上传文件
<form action='' method='post' enctype ='multipart/form-data'>
首先必须是 post请求 其次 要配置 enctype属性
后端获取文件
request.FILES.get('file')
这样来接受文件对象
然后储存文件
with open(file_obj.name,'wb') as f:
for line in file_obj:
f.write(line)
request对象基本方法
request.method
获取请求方式
request.POST
获取post请求提交的普通键值对数据 不包括文件
request.GET
获取get请求
request.FILES
获取文件
request.path
获取用户访问的路由
request.path_info
request.get_full_path()
获取用户访问的路由及问号后面携带的参数
FBV与CBV
FBV是基于函数的是视图
CBV是基于类的视图
CBV是创建类 路由访问类里面的方法
from django.views import View
class Mylogin(View):
def get(self,request):
return render(request,'login.html')
def post(self,request):
return render(request,'login.html')
使用CBV和路由匹配时 需要用关键词 as_view() 方法
urlpatterns = [
path('login/', views.Mylogin.as_view()),
]
'''
FBV和CBV各有千秋
CBV特点能够直接根据请求方式不同匹配到对应的方法执行
CBV源码解析
封装了一个函数,作为对应路由的函数
封装的函数中,让我们的自定义类产生了一个对象,并让对象执行方法dispatch返回结果
dispatch辨认了请求方式,根据请求方式返回了某个类体函数的结果(HttpResponse对象)
模板层语法传递数据
前端语法:
{{}}:主要与数据值相关
{%%}:主要与逻辑相关
前端html文件中可以使用
{{获取到后端传送的数据}}
<p> {{ name }} </p>
<p> {{ age }} </p>
<P> {{ list.1}} </p>
针对可以进行索引取值的数据 可以通过.数字的方法进行索引取值
给后端发送数据
<a href="{% url 'a01' '123' %}">点我</a>
# 跳转到 别名为 a01的路由 顺便给这个路由对应的函数 传递参数123
后端python文件中
#方式一:
def login(request):
name = '张无忌'
age = 22
return render(request,'login.html',{'name'=name})
#精准传值 不浪费资源 针对多资源的传递书写麻烦 优点:不浪费资源
#方式二:关键词 locals()
def login(request):
name = '张无忌'
age = 22
return render(request,'login.html',locals())
#将方法中所有的变量名与值全部和html文件一起传送过去
#优点方便一下传所有 缺点不够精准 浪费资源
后端传值特性
1.基本数据类型都可以传递
2.对象也可以传
3.文件对象也可以展示并调用方法
4.函数名会自动加括号执行并将返回值展示到页面上(不支持额外传参)
5.类名也会自动加括号调用
ps:总结针对可以加括号调用的名字模板语法都会自动加括号调用
模板层之过滤器
在Django的模板语言中,通过使用 过滤器 来改变变量的显示
使用管道符"|"来应用过滤器
在前端使用 可以对数据进行2次加工
{{value|length}} 返回值的长度
{{value|filesizeformat}} 字段转换数字单位 变为文件大小
{{value|slice:"0:5"}} 对数据进行切片展示 索引0-5
{{ value|date:"Y-m-d H:i:s"}} 可以对时间进行格式化展示 '2022-01-19 18:12:23'
{{ value|safe}} 后端返回的值为前端标签时 控制是否直接展示
{{ value|truncatechars:9}} 如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:截断的字符数
{{ value|truncatewords:9}} 在一定数量的字后截断字符串。
{{ value|cut:' ' }}
移除value指定字符
如果value为'i love you',那么将输出'iloveyou'.
模板层之逻辑判断
django中前端也是可以做逻辑判断的
if判断
{% if name == 'moon'%}
条件符号执行的代码
{% elif name == '123'%}
条件符号执行的代码
{% else %}
以上条件都不符号时执行的代码
{% endif %}
固定语法一定要有结束 {% endif %
for循环
{% for book_obj in book_obj_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book_obj.name }}</td>
<td>{{ book_obj.time|date:'Y-m-d' }}
</td>
{% endfor %}
for循环有自带方法
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是不是第一次循环(布尔值)
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环
模板的继承与导入
html的复用
可以设置哪些可以变
关键词 母版设置可变区域
{% block 别名 %}
{% endblock %}
如何引入模板
{% extends '母版文件名' %}
然后直接在内容区域编写改变的代码
{% block 母版可修改位置 %}
# 正常母版有3个可以修改的位置
{% endblock %}
ps:模板中至少应该有三个区域
页面内容区、css样式区、js代码区
测试环境
创建一个text.py文件
导入模块 from django.test import TestCase
然后去manage.py中复制前两行
然后在 def main函数中 导入模块
import django
django.setup()
这样就可以测试你的代码了
如何时时查看orm底层执行的sql文件
sttings文件中配置
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level': 'DEBUG',
},
}
}
这样每次运行models命令都会显示对于的sql语句
orm常用关键字
create
表中新增数据,并有返回值是创建的对象本身
res = models.User.objects.create(name='moon',age=18)
filter()
筛选 支持多个条件 默认是 多个条件是and关系
res = models.User.objects.filter(name='moon')
update()
更新数据 搭配筛选来决定更新的个数
res = models.User.objects.filter(id=1).update(age=22)
delete()
删除数据 搭配筛选来决定删除的个数
res = models.User.objects.filter(id=1).delete()
all()
查询所有数据
models.User.objects.all()
values()
models.User.objects.filter(id=1).values('name')
print(res) # <QuerySet [{},{},{}]> 列表套字典
# #获取user表中id为1的数据 的 name字段的值
values_list()
指定字段获取内容
# <QuerySet [('duo',), ('bo',), ('duoduo',), ('bo',), ('hong',)]>
distinct()
将查询的结果去重,不影响数据库中的数据
models.User.objects.values('name','age').distinct()
order_by()
根据指定条件排序 默认升序
models.User.objects.order_by('age')
# user表进行排序 排序根据为age 默认升序 从小到大
count()
models.User.objects.filter(age=22).count()
# 统计user表中 age是22的有几个
ORM执行编写SQL语句
复杂数据查询时候orm的操作效率可能比较低 没有原生的sql效率高,我们也可以自己编写sql
raw方法
res = models.User.objects.raw('select * from app01_user;')
方式二:
from django.db import connection
cursor = connection.cursor()
cursor.execute('select name from app01_user;')
print(cursor.fetchall())
# 利用模块生成 cursor对象 然后利用cursor执行sql语句
# cursor.fetchall() 接收反馈结果
双下划线查询
大于 小于 大于等于 小于等于 区间 包含等查询方式
更多筛选方式
通过.filter()方法获得数据,支持双下划线查询
models.User.objects.filter(age__gt=18)
# 查询年龄大于18的数据对象
models.User.objects.filter(age__lt=18)
# 查询年龄小于18的数据对象
models.User.objects.filter(age__gte=18)
#大于等于
models.User.objects.filter(age__lte=18)
#小于等于
models.User.objects.filter(age__in=(18,28,38))
# 查询年龄是 18 或者 28 或者 38的数据对象
models.User.objects.filter(age__range=(10,20))
# 查询年龄从10到20岁 之间 的数据对象
models.User.objects.filter(name__contains='m')
# 查询name字段中 包含 'm' 的数据对象 不包括大写M
models.User.objects.filter(name__icontains='m')
# 也包含大写的M
ORM表外键字段的创建
一对多
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
# 在表中建立外接字段
多对多
外键字段名 = models.ManyToManyField(to='关联表名')
一对一
author_info = models.OneToOneField(to='Author_info')
外键字段的增删改查
一对一或者一对多
models.Book.objects.create (name='西记',price='100',publish_id=1)
# 直接在外键添加实际字段 填写id
models.Book.objects.create(name='西记',price='100',publish=publish_obj)
# 或者直接添加对象
models.Publish.objects.filter(pk=2).delete()
models.Publish.objects.filter(pk=2).update(publish_id=2)
models.Publish.objects.filter(pk=2).update(publish=publish_obj
多对多
直接使用对象点第三张表的方式
add添加
book_obj.authors.add(1,3)
# 这样相当于 给书的这个对象 绑定了 1和3 2个id的作者
book_obj.authors.add(author_obj,author_obj2)
也支持直接放入一个对象
删除:
remove
book_obj.authors.remove(1,3)
book_obj.authors.remove(author_obj,author_obj2)
修改:
set
book_obj.authors.set([1,3])
# 把数据对应的作者关系 更改为 这本书 对应作者id为 1和3
清空:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear()
# 直接去authors这个表里面取消所有相关的绑定关系
正反向的概念
关键是看 外键字段在哪里
加入由书查出版社
因为外键字段在书内 所以就是正向查询
出版社查书 因为出版社内没有外键字段 就是 反向查询
多表查询
正向查询按字段
反向查询按表名小写
正向查询
查询书籍id为1的 出版社名称
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish.name
查询作者为'moon'的电话号码
authors_obj = models.Authors.objects.filter(name='moon').first()
authors_obj.info.phone
ORM跨表查询的口诀(重要)
正向查询按外键字段
反向查询按表名小写
反向查询
查询是东方出版社出版的书
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
publish_obj.book_set.all()
当你的查询结果是多个的时候 必须要用 _set.all()
联表查询(基于双下划线方法的)
1.查询作者'moon'的 手机号
authors_obj = models.Authors.objects.filter(name='moon').
2.查询数据id为1的出版社名称和书的名称
models.Book.objects.filter(pk=1).values(publish__name,name)
直接通过 ————跨表查询
ORM聚合查询
1.Max 最大值
2.Min 最小值
3.Sun 求和
4.Count 次数
5.Avg 平均值
未分组查询时需要关键词 aggregate
eg:查询商品表中所有商品价格的总和
models.Goods.objects.all().aggregate(Sun('price'))
models.Goods.objects.all().aggregate(Sun('price'),Max('supply'),Min('price')
# 同时获取 这个表中 不同的字段数据 price字段的和 supply字段的最大值等等
分组查询
分组关键字 annotate()
eg:统计每一本书的作者个数
一般只要需求中带有每个 每一个等词语 都是需要以此来分组比较合适
models.Book.objects.annotate
(author_num=Count('author__pk')).values('name','author_num')
# models.后面是什么就是根据什么分组 目前来看是根据Book来分组
# 然后获取分组后 统计出来每本书对应的作者个数 Count('author__pk')
# 最后展示 书的名字 和 对应的作者个数
eg:统计不止一个作者的图书
res = models.Author.objects.annotate(author_num=Count(authors))
.filter(author_num__gt=1).values('name','author_num')
# 先根据作者进行分组 求出每一本书对于的作者个数 author_num=Count(authors)
# 然后在过滤出作者个数大于1的作者对象 最后选择展示内容
'''
只要你手上是一个QuerySet对象 都可以使用 filter方法再次过滤
'''
F查询
**针对字段进行分组 **
eg:查出卖出数大于库存数的书籍
res = models.Book.objects.filter(maichu__gt=F('kuncun'))
使用f查询可以直接拿到字段的值
eg:将所有书的名称后面加上 打折
from django.db.models.functions import Concat
models.Book.objects.update(name=Concat(F('name').Value('打折')))
# F不可以直接做字符串的拼接 如果要做字符串的拼接需要导入 Concat模块
# 设置字符串的拼接 Concat(F('name').Value('打折')
Q查询
改变条件的链接关系
# filter(内默认是and关系)
eg:查询卖出数大于100或者价格小于600的书籍
from django.db.models import Q
models.Book.objects.filter(Q(maichu__gt=100)|Q(price__lt=600)
# 可以使用大Q包裹 然后 可以改变条件关系
Q(条件),Q(条件) = and
Q(条件)|Q(条件) = or
~Q(条件)|~Q(条件) = not
标签:name,models,django,filter,objects,login,查询,周报
From: https://www.cnblogs.com/moongodnnn/p/16991005.html