目录
django
路由层
django请求生命周期流程图(*****)
django请求生命周期的含义:当用户在浏览器输入URL到用户看到网页的这个时间段内,django后台所发生的事情
1.路由匹配
urlpatterns = [
path('^admin/', admin.site.urls),
# 首页 默认进去
path('^$',views.home),
# 路由匹配
path('^test/$',views.test),
path('^testadd/$',views.testadd),
# 尾页(了解 后期异常捕获)
path('',views.error),
]
解析:
^ : 开头
$ : 结尾
2. 正则匹配
django2.X及以上版本有re_path 第一个参数是正则
匹配的本质是只要第一个正则表达式能够从用户输入的路由中匹配到数据就算匹配成功会立刻停止路由层其他的匹配直接执行对应的视图函数
re_path('^test/$', views.test)
django1.X路由匹配使用的是url() 功能与django2.X及以上的re_path()一致
3.正则匹配的无名有名分组
无名分组
分组就是给某一段正则表达式用小括号括起来
re_path('^test/(\d{4})/', views.test)
无名分组:会将括号内正则表达式匹配到的内容当做位置参数传递给视图函数
有名分组
re_path('^test/(?P<year>\d{4})/', views.test)
有名分组:会将括号内正则表达式匹配到的内容当做关键字参数传递给视图函数
注意上述的分组不能混合使用!!!
反向解析
但路由频繁变化的时候,html页面与后端上的连接地址如何做到动态解析呢?
通过在url里面设置路由和视图函数的别名,动态解析出对应的路由,该路由直接执行对应的函数,函数直接执行对应的url
1.概念
通过一些方法得到一个结果 该结果可以直接访问对应的url触发视图函数 实现url路由频繁变化,html界面与后端动态解析连接地址操作步骤:
基本使用
1.方向解析器路由配置
path('login001/', views.login, name='login_view') # name='login_view' 起别名
前后端反向解析
2.导入模块reverse
from django.shortcuts import render,HttpResponse,redirect,reverse
3.反向解析 reverse('login_view')
def home(request):
print(reverse('login_view'))
return render(request,'home.html')
前端反向解析
4.前端模板文件反向解析
<a href="{% url 'login_view' %}">111</a>
动态路由的反向解析
path('func1/<str:others>/', views.func1_func, name='func1_view')
html页面上模板语法 {% url 'func1_view' 'jason' %}
后端语法 reverse('func1_view', args=('嘿嘿嘿',))
路由分发
django支持每个应用都可以由自己独立的路由层(url.py)、静态文件(static文件夹)、模板层(templates)。基于该特性多人开发项目就可以完全解耦合,之后利用路由分发还可以整合到一起
1.需要导入一个include路由分发模块
from django.urls import path,include
2.总路由分发 简易>>>推荐
urlpatterns = [
# 路由分发终极写法 简便
path('app01/',include('app01.urls')),
path('app02/',include('app02.urls'))
子路由
from django.urls import path
from app01 import views
urlpatterns = [
path('index/',views.index)
]
起别名
1.总路由
urlpatterns = [
path('admin/', admin.site.urls),
# 路由分发
path('app01/',include('app01.urls')),
path('app02/',include('app02.urls'))
]
2.子路由
urlpatterns = [
path('index/',views.index,name='app01_index_view')
path('index/',views.index,name='app02_index_view')
]
3.后端
reverse('app01_index_view')
reverse('app02_index_view')
视图层
django视图层:Django项目下的views.py文件,它的内部是一系列的函数或者是类,用来处理客户端的请求后处理并返回相应的数据
必会三板斧
三板斧
HttpResponse # 返回字符串
render # 返回html页面,并且在返回浏览器之前还可以给html文件传值
redirect # 重定向
三板斧具体详细参数
1.HttpResponse
class HttpResponse(HttpResponseBase):
pass
# 括号内直接跟一个具体的字符串作为响应体
2.render
def render(request, template_name, context=None, content_type=None, status=None, using=None):
# 参数:
request: 用于生成响应的请求对象。
template_name:要使用的模板的完整名称,可选的参数
context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
3.redirect
def redirect(to, *args, permanent=False, **kwargs):
传递要重定向的一个硬编码的URL或者路由
class HttpResponseRedirectBase(HttpResponse):
eg: redirect内部是继承了HttpRespone类
判断下面这句话的对错?
问:用来处理请求的视图函数都必须返回httpResponse对象
答:正确
class HttpResponse:
pass
return HttpResponse()
def render(request, template_name):
return HttpResponse()
return render()
def redirect():
redirect_class =类(祖先有个类是HttpResponse)
return redirect_class()
return redirect()
JsonResponse对象
前后端数据交互需要使用到json作为序列化,实现跨语言数据传输。
1. 混合开发项目:前端页面和后端代码写到一块
2. 前后端分离项目:前端是一个项目,后端是一个项目,后端只需要写接口
前端序列化 后端序列化
JSON.stringify() json.dumps()
JSON.parse() json.loads()
JsonResponse序列化
# 导入JsonResponse模块
from django.http import JsonResponse
def jason_func(request):
# 将后端字典序列化发送到前端
user_dict = {'name': 'kimi老师', 'age': 18}
# JsonResponse自动编码并返回给前端页面
return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})
本质看源码:
user_dict,json_dumps_params={'ensure_ascii':False} :解决前端汉字转码问题
JsonResponse主要序列化字典 针对非字典的其他可以被序列化的数据需要修改safe参数为False(是在前端页面更改的)
如列表
# 列表
l1=[11,22,33,44]
return JsonResponse(l1,json_dumps_params={'ensure_ascii':False},safe=False)
是否可以被序列化看通过json.JSONEncoder 查看源码
request对象获取文件
form表单携带文件类型的数据需要做到以下几点
1.method必须是post
2.enctype必须是multipart/form-data
django后端需要通过request.FILES获取文件类型的数据
request对象方法
1.获取请求方式POST/GET
request.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
2.request.POST
获取POST请求提交普通的键值对数据 一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成
3.获取GET请求
request.GET
获取GET请求 一个类似于字典的对象,包含 HTTP GET 的所有参数
4.获取文件
request.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。
5.原生的浏览器发过来的二进制数据
request.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,
例如:二进制图片、XML,Json等。
6.拿到路由
request.path
个字符串,表示请求的路径组件(不含域名)
7.拿到路由
request.path_info
8.能过获取完整的url及问号后面的参数
request.get_full_path()
FBV与CBV
FBV
基于函数的视图
def index(request):return HttpResponse对象
CBV
基于类的视图
from django import views
class MyLoginView(views.View):
def get(self, request):
return HttpResponse('from CBV get function')
def post(self, request):
return HttpResponse('from CBV post function')
path('login/', views.MyLoginView.as_view())
会自动根据请求方法的不同自动匹配对应的方法并执行
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的模板语法是自己写的 跟jinja2不一样
1.针对需要加括号调用的名字 django模板语法会自动加括号调用你只需要写名字就行
2.模板语法的注释前端浏览器是无法查看的 {##}
3.
"""
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.模板语法之过滤器(内置函数)
模板层之标签
数据来源djangoproject
标签之forloop关键字
forloop模板语法自带的变量名
标签之if判断
格式:
{% if 条件1(可以自己写也可以用传递过来的数据) %}
<p>今天又是周三了</p>
{% elif 条件2(可以自己写也可以用传递过来的数据) %}
<p>我是列表</p>
{% else %}
<p>我是else分支的!</p>
{% endif %}
eg:
# if判断
判断a是True打印
{% if a %}
<p>今天又是周三了</p>
{% elif l1 %}
<p>我是列表</p>
{% else %}
<p>我是else分支的</p>
{% endif %}
判断a传过来是true,打印今天又是周三了;a为false,则打印我是列表
a和l1都为false,则打印else分支
标签之for循环
解析:
forloop内置对象:运行结果解析
'counter0': 从0开始计数
'counter' : 从1开始计数
'first': True,判断循环的开始
'last' : Tues,判断循环的结束
for循环代码展示:
{% for i in l1 %}
<p>{{ forloop }}</p>
<p>{{ i }}</p>
{% endfor %}
标签for与if混合使用及标签之empty
# for与if混合使用
{% for foo in l1 %}
{% if forloop.first %}
<p>这是我第一次循环</p>
{% elif forloop.last %}
<p>我是最后一次循环</p>
{% else %}
<p>{{ foo }}</p>
{% endif %}
{% empty %}
<p>for循环的可迭代对象内部没有元素,根本没法循环</p>
{% endfor %}
解析:
forloop.first: 判断本次循环是不是第一次,是,就执行下面的代码
forloop.last: 判断本次循环是不是最后一次,是,就执行下面代码
empty: 你给我传的数据是空的无法循环取值(空字符串、空列表、空字典)
循环字典
indexPage.html
# 循环字典
1.循环键
{% for r in d1 %}
<p>{{ r }}</p>
{% endfor %}
2.循环键keys
{% for foo in d1.keys %}
<p>{{ foo }}</p>
{% endfor %}
3.循环值values
{% for foo in d1.values %}
<p>{{ foo }}</p>
{% endfor %}
4.items
{% for foo in d1.items %}
<p>{{ foo }}</p>
{% endfor %}
解析:
.items : 返回可遍历的(键, 值) 元组数组。
with起别名
django模板语法取值操作>>>:只支持句点符
句点符既可以点索引也可以点键
{{ d1.hobby.2.a1 }}
with起别名:拿到字典中a的值
{% with d1.hobby.2.a as a_name %}
<p>{{ a_name }}</p>
{% endwith %}
在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
# 输出 我是a
命名规范: 只能在with代码块儿的范围之内才能使用别名
模型层的views.py
def index_func(request):
a=100
# a=True
# l1=[12,23,34,45,56,67]
L1=[]
s=(11,22,33,44)
d1={'name':'kimi','age':19,'hobby':['read','music',{'a':'我是a','b':'我是b'}]}
return render(request,'indexPage.html',locals())
自定义过滤器、标签及inclusion_tag(了解)
如果想要自定义一些模板语法 需要先完成下列的三步走战略
1.在应用下创建一个名字必须叫templatetags的目录
2.在上述目录下创建任意名称的py文件 ,如mytag.py
3.在上述py文件内先编写两行固定的代码
from django import template
register = template.Library()
1.自定义过滤器(最大只能接收两个参数)
1.mytag.py
from django import template
register = template.library()
# 自定义过滤器(最大只能接收两个参数)
# 参数 过滤器 过滤器名字
@register.filter(name='myadd')
def my_sum(a,b):
return a+b
2.indexPage.html
# 加载过滤器
{% load mytags %}
<p>{{ n|myadd:100 }}</p>
3.后端
def index_func(request):
n=888
return render(request,'indexPage.html',locals())
4.前端页面结果是:988
2.自定义标签(参数没有限制)
1.mytag.py
from django import template
register = template.library()
# 自定义标签(参数没有限制)
# 参数 过滤器 过滤器名字
@register.simple_tag(name='mytag')
def my_tag(a,b,c,d):
return f'{a}-{b}-{c}-{d}'
2.indexPage.html
# 加载过滤器
{% load mytags %}
<p>{%mytag 'kimi' 'jason' 'kiki' 123 %}</p>
3.自定义inclusion_tag(局部的html代码)
1.mytag.py
from django import template
register = template.library()
# 自定义局部html
@register.inclusion_tag('menu.html',name='mymenu')
def my_menu(n):
html=[]
for i in range(n):
html.append('<li>第%s</li>'%i)
return locals()
2.indexPage.html
# 加载过滤器
{% load mytag %}
{% mymenu 10 %}
3.自定义的网页html
<ul>
{% for foo in html %}
{{ foo|safe }}
{% endfor %}
</ul>
总结:
1.自定义过滤器和自定义标签:在页面上通过特殊的语法,然后能调用mytag.py的函数,将函数返回值调用到标签或者过滤器的位置
2.自定义:在页面上通过特殊的语法,然后能调用py的函数将函数返回值传给到局部的页面html,将返回值渲染后返回给函数
模板的 继承与导入
模板的继承
当我们多个页面有相似的页面,我们可以采用下列方法
1.我们直接复制粘贴>>>创建一个新的html
2.模板的继承
1.在模板中使用block划定子板>>方便以后修改的区域
{% block 区域名称 %}
{% endblock%}
2.子版继承母板
{% extends 'home.html'%}
{% block 区域名称 %}
子板自己的内容
{% endblock%}
注意:子板也可以继续使用子模板的内容
{{block.super}}
关于模板中的继承,,至少有三个区域的模板可以继承去渲染,分别是页面内容区、CSS样式区、JS代码区
模板的导入
提前将被导入的html页面写好,其他html页面想使用就可以导入
导入的格式
{% include '导入的html文件名'%}
eg:
{% include 'myform.html'%}
模型层
ORM常见关键字
create | 描述 |
---|---|
filter | 创建数据并直接获取当前创建的数据对象 |
first/last | 根据条件筛选数据 结果是QuerySet [数据对象1,数据对象2] |
update | 拿queryset里面第一个元素/拿queryset里面最后一个元素 |
delete | 删除数据(批量删除) |
all | 查询所有数据 结果是QuerySet [数据对象1,数据对象2] |
values | 根据指定字段获取数据 结果是QuerySet [{}},{},{},{}] |
values_list | 根据指定字段获取数据 结果是QuerySet [(),(),(),()] |
distinct | 去重 数据一定要一模一样才可以 如果有主键肯定不行 |
order_by | 根据指定条件排序 默认是升序 字段前面加负号就是降序 |
get | 根据条件筛选数据并直接获取到数据对象 一旦条件不存在会直接报错 不建议使用 |
exclude | 取反操作 |
reverse | 颠倒顺序(被操作的对象必须是已经排过序的才可以) |
count | 统计结果集中数据的个数 |
exists | 判断结果集中是否含有数据 如果有则返回True 没有则返回False |
神奇的双下划线
数据查询(双下划线)
__gt | 大于 |
---|---|
__lt | 小于 |
__gte | 大于等于 |
__lte | 小于等于 |
__in | 类似于成员运算,在...里面 |
__range | 在什么范围之内 |
__contains | 是否含有,区分大小写 |
__icontains | 是否含有,不区分大小写 |
__year | 查询年份 |
__day | 查询日期天数 |
__second/minute | 查看秒/分 |
ORM外键字段的创建
1.一对多 外键字段建在多的一方
2.多对多 外键字段统一建在第三张关系表
3.一对一 建在任何一方都可以,但是建议建在查询频率较高的表中
注意:目前关系的判断可以采用表与表之间换位思考原则
一对多 ORM与MySQL一致 外键建在多的一方
多对多 ORM比MySQL有更多的变化
1.外键字段可以直接建在某张表中(查询频率较高的)
内部会自动帮你创建第三张关系表
2.自己创建第三张关系表并创建外键字段
后续讲解
一对一 ORM与MySQL一致 外键字段建在查询较高的一方
1.一对多关系
publish= models.ForeignKey(to='Publish',on_delete=models.CASCADE)
2.一对一
author_detail = models.OneToField(to='AuthorDetail',on_delete=models.CASCADE)
3.多对多
authors=models.ManyToManyField(to='Author')
跨表操作
1.正反向查询的概念
正向查询
从有外键字段的表查询关联表的数据
反向查询
从没有外键字段的表查询关联表的数据
核心就是看外键字段
口诀
正向查询按外键字段
反向查询按表名小写
2.基于对象的跨表查询(子查询)
相当于mysql中的子查询
( 1)先根据已知条件获取到一个具体的数据对象
( 2)基于该数据对象运用正反向查询的口诀完成
4.基于双下划线的跨表查询
反向的口诀也使用与values或者values_list中使用
聚合查询
聚合函数:Max Min Sum Count Avg
函数名 | 描述 |
---|---|
Max | 大于 |
Min | 小于 |
Sum | 求和 |
Count | 统计某个数据 |
Avg | 平均值 |
1.聚合函数:
max min sum count avg
在ORM中指出单独使用聚合函数,通过关键字aggregate
2.导入聚合函数
from django.db.models import Max,Min,Sum,Count,Avg
models.表名.onjects.aggregate(别名=Max('字段名'), 别名=Min('字段名'), 别名=Sum('字段名'), 别名=Avg('字段名'), 别名=Count('字段名'))
分组查询
1.通过关键字annotate,进行分组查询
2.分组依据
models.表名.objects.annotate() 按照表分组
models.表名.objects.values('字段名').annotate 按照values括号内指定的字段分组
3.语法
models.Book.objects.annotate(聚合函数分组一句).filter(筛选条件相当于having).values('字段名')
F查询与Q查
# 导入F,Q
from django.db.models import F, Q
1.F查询
F查询为当前查询条件不明确,也需要从数据库中获取时使用的
2.Q查询
Q查询为执行条件之间的关系为与或非时使用的
标签:总结,request,django,周末,html,模板,path,路由,12.18
From: https://www.cnblogs.com/zhanglanhua/p/16991066.html