视图层 FBV和CBV 模板层
视图层 FBV和CBV 模板层
-
django请求生命周期流程图
浏览器发送请求(数据格式遵循http格式) web服务网关接口(django默认的wsgiref,,生产环境会换成uwsgi) 整个jango 中间件(类似于django的保安 门户) 路由层(urls 路由匹配) 视图层(views 核心逻辑) 模板层(templates html文件) 模型层(models orm操作数据库的操作)
-
路由匹配
django1.X版本中路由匹配使用的方法是url() url(正则表达式,视图函数内存地址) django2.X、django3.X版本中路由匹配使用的方法是path() path(精准匹配,视图函数内存地址) reg_path() == url() 只要能够匹配到内容就会自动触发视图函数的执行并且结束匹配 # django自动添加斜杠后缀 APPEND_SLASH = True
-
无名分组有名分组
无名分组:将括号内正则表达式匹配到的内容当做位置参数传递给视图函数 url(r'^index/(\d+)/',views.index) 有名分组:将括号内正则表达式匹配到的内容当做关键字参数传递给视图函数 url(r'^index/(?P<year>\d+)/',views.index)
-
反向解析
url(r'^index/',views.index,name='my_index') #ruls reverse('my_index') # index/ 后端解析 {% url 'my_index' %} # index/ 前端解析
-
无名有名反向解析
url(r'^index/(\d+)/',views.index,name='my_index') #urls 无名分组 reverse('my_index',args=(111,)) # index/111/ #后端解析 {% url 'my_index' 222 %} # index/222/ #前端解析 url(r'^index/(?P<year>\d+)/',views.index,name='my_index') #有名分组 reverse('my_index',kwargs={'year':123}) # index/123/ #后端解析 {% url 'my_index' year=555 %} # index/555/ #前端解析 # 支持简写 reverse('my_index',args=(123,)) # index/123/ #后端解析 {% url 'my_index' 555 %} # index/555/ #前端解析 #都依照无名分组解析方法解析就可以
-
路由分发
将路由与视图函数的对应关系拆分到不同的app中各自管理 总路由只做分配操作 """ django支持每个app都有自己独立的路由层、模板层、静态文件夹 """ 总路由(斜杠后面千万不要加$符) url(r'app01/',include('app01.urls')) url(r'app02/',include('app02.urls')) 子路由 url(r'^index/',views.index)
-
名称空间(了解)
# 原因:需要用到名称空间完全是因为反向解析起别名名字冲突造成的 总路由(斜杠后面千万不要加$符) url(r'app01/',include('app01.urls',namespace='app01')) url(r'app02/',include('app02.urls',namespace='app02')) reverse('app01:index') reverse('app02:index') {% url 'app01:index' %} {% url 'app02:index' %} """名称空间其实完全可以不使用 只要确保别名不冲突即可 app01_index诸如此类"""
-
伪静态(了解)
将网址故意设计成某个具体文件地址 路由层里指定加一个.html后缀 没啥用 就是看着像静态文件
-
虚拟环境(了解)
虚拟环境类似于一个个全新的python解释器 可以针对不同的项目做专门的配置 虚拟环境的特征标识 venv文件夹 # 不要一直使用虚拟环境(尤其是学习阶段)
-
视图层
小白必会三板斧 Httpresponse render redirect JsonResponse form表单发送文件
-
FBV与CBV
FBV基于函数的视图 F:def 自己理解 CBV基于类的视图 C:class 自己理解
-
模板层
模板语法的传值 模板语法之过滤器 模板语法之标签 自定义过滤器、标签、inclusion_tag 模板的继承与导入
小白必会三板斧
from django.shortcuts import render,HttpResponse,redirect #导入三板斧的模块 记住
# 视图函数必须返回一个HttpResponse对象
#如果没有return 那么在python里 没有return 默认返回None
报错信息:
ValueError at /index/
The view app01.views.index didn't return an HttpResponse object. It returned None instead.
app01.views没有返回一个HttpResponse对象 他返回了None
引出了新的问题 三板斧 都返回的是什么
HttpResponse
class HttpResponse:
pass
点进HttpResponse的源码发现他是一个类 那么 类加括号 得到一个对象 所以推断出 HttpResponse 返回的是一个HttpResponse对象
render
def render(...):
return HttpResponse(...)
点进render的源码 发现他是一个函数 他返回的值是 HTtpResponse() 也是一个HttpResponse对象
redirect
def redirect(...)
# redirect_class是HttpResponse子类
return redirect_class(...)
发现return一个不认识的redirect_class 然后上面有个if 发现不管是成不成立他返回的都继承HttpResponse 所以这个函数返回的也是HttpResponse对象
JsonResponse(使用频率高很多)
"""
前后端不分离
django写项目(前端直接使用模板层及模板语法)
前后端分离
django写项目(前端使用其他框架和语言)
不同编程语言之间如何交互???
json格式数据
python中序列化反序列化的方法
dumps()
loads()
js中序列化反序列化的方法
JSON.stringfy()
JSON.parse()
"""
使用json
在index函数里要给前端返回一个字典
def index(request):
d={'username':'uzi','pwd':123}
json_str=json.dumps(d)
return HttpResponse(json_str)
#发现返回的是字典 里面加了双引号 这是json的格式才会用双引号
{"username": "uzi", "pwd": 123}
#字典如果有汉字呢 会返回吗 不会 前端把汉字转码了
字典: d={'username':'uzi永远的神','pwd':123}
{"username": "uzi\u6c38\u8fdc\u7684\u795e", "pwd": 123}
#那么如何解决呢 先看源码
#json序列化时 加一个参数 ensure_ascii 不让他转码
json_str=json.dumps(d,ensure_ascii=False)
#但是不想手动转json格式 也可以导入一个模块 然后retrun JSONResponse自动转成json格式的数据 他里面也封装了dumps
from django.http import JsonResponse 记一下
d={'username':'uzi永远的神','pwd':123}
return JsonResponse(d)
#前端数据
{"username": "uzi\u6c38\u8fdc\u7684\u795e", "pwd": 123}
#使用JSONResponse 也想传中文
打开JsonResponse源码 留下了用到的
class JsonResponse(HttpResponse):
#3.发现形参json_dumps_params=None 可以给他更改成一个字典
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
#2.发现json_dumps_params=None 就是一个空字典 如果给他一个字典 他就不会变成空字典
if json_dumps_params is None:
json_dumps_params = {}
kwargs.setdefault('content_type', 'application/json')
#1.这块发现调用了dumps 如果给他一个ensure_ascii=False 就可以解决 ,发现有个**打散 那么传给他一个字典ensure_ascii:False 他就会打散成关键字参数
data = json.dumps(data, cls=encoder, **json_dumps_params)
super(JsonResponse, self).__init__(content=data, **kwargs)
#函数里 指定json_dumps_params等于一个字典 ,源码显他不为None 所以不是空字典 然后打散成关键字形参
ensure_ascii=False 放在dumps里 也让他中文显示了
return JsonResponse(d,json_dumps_params={'ensure_ascii':False})
#前端返回结果
{"username": "uzi永远的神", "pwd": 123}
json.encoder 点encoder可以查看json序列化支持的类型和转换后的类型
#使用JsonResponse返回一个列表发现报错
In order to allow non-dict objects to be serialized set the safe parameter to False.
为了允许非字典对象序列化,将safe参数设置为False。
加上一个参数safe=False就好了
return JsonResponse(l,safe=False)
#其他类型转成json格式都要加一个false 集合类型不能转换成json序列化的对象
form表单提交文件
提交post请求时候报错
Forbidden (403)#权限不够
CSRF verification failed. Request aborted.
记得去settings里把 'django.middleware.csrf.CsrfViewMiddleware', 注释掉
1.method必须是post
2.enctype参数必须是multipart/form-data
request.POST无法获取到文件类型的数据
request.FILES获取文件类型的数据
#以及获取数据放到内存了
<MultiValueDict: {'file': [<InMemoryUploadedFile: bug.jpg (image/jpeg)>]}>
前端获取文件数据 multiple
<input type="file" name="file"> 只能获取一个
<input type="file" name="file" multiple> 可以一次性获取多个
后端获取文件数据
request.FILES.get('名字') #获取文件对象单个
request.FILES.getlist() #获取多个文件对象
#传单个文件
if request.method=='POST':
# print(request.POST)
# print(request.FILES)
file_obj=request.FILES.get('file') #获取文件对象
print(file_obj) #
with open(file_obj.name,'wb')as f:
for line in file_obj:
f.write(line)
FBV和CBV简介
#视图函数可以是函数 也可以是类
FBV 基于函数的视图 (前后端不分离)
def index(request):
return HttpResponse(...)
CBV 基于类的视图 (前后端分离)
from django.views import View #先导入模块
class Mylogin(View): #需要继承view
def get(self,request):
return HttpResponse('get请求')
def post(self,request):
return HttpResponse('post请求')
#CBV会自动识别请求是get还是post然后进入对应函数
路由配置
#FBV路由配置
url(r'^index/',views.index),
#CBV路由配置
url(r'^login/',views.Mylogin.as_view()) #配置有点不一样和FBV
CBV源码
路由层
url(r'^login/',views.Mylogin.as_view())
视图层
from django.views import View
class Mylogin(View):
def get(self,request):
return HttpResponse('get请求')
def post(self,request):
return HttpResponse('post请求')
---------------------------------------------------------------
1.在哪入口 发现 路由配置那块有问题 ,mylogin为一个类,类.as_view()从而证明这个as_view可能是一个普通函数
也可能是一个绑定给类的方法(classmethod) 类来调用把类当成第一个默认参数传过去,研究这个as_view
类调用方法 ,照这个as_view的位置 由于他是类调用 直接去类本身找没有然后去父类找 找到了
"""
函数名或者方法名遇到括号执行优先级最高
对象查找属性或方法的顺序
永远都是先从自己身上找
然后去产生对象的类中找
再去类的父类中找 如果都没有才会报错
闭包函数
定义在函数内部并且使用了外层函数名称空间中的名字
FBV与CBV在路由匹配上本质其实是一样的
核心代码
url(r'^login/', views.MyLogin.as_view())
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
# cls使我们自定义的类 MyLogin
self = cls(**initkwargs) # 产生一个MyLogin类的对象 obj
return self.dispatch(request, *args, **kwargs)
return view
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
"""
2. 根据查找顺序 他是mylogin.函数名(),所以先去自己本身找 自己本身就是一个类 ,找了没有,然后去父类找 发现继承了View 查找View
3.发现View这个类里有as_view这个方法 这个方法是绑定给类的
4.as_view 返回值是view 这个方法 这个方法在上面
views.Mylogin.as_view() == views.view()
Mylogin.as_view() == 类调方法并执行 ==as_view==as_view返回值 view
5.view函数里面 定义了一个类的对象self,并给self赋值 返回值是return self.dispatch(xxx)
self 是类的对象 先去他里面找dispatch这个方法 没有
去他的类找dispatch这个方法 没有
去他的父类找 有的
6.打开dispatch这个方法
#请求方法转小写 并判断是否在对象的http_method_names这个变量里
if request.method.lower() in self.http_method_names:
#利用了反射 getattr(对象,转小写的请求方法,后面这个先不看) handler=对象产生的类里面的方法内存地址
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
#执行并返回结果
return handler(request, *args, **kwargs)
模板语法传值
#给前端界面传值
1.python基本数据类型全部支持模板语法传值
2.在django中模板语法取值只能使用一种方式(句点符.) django前端取值只能用点的方式
{{ d.name }} 去key对应的值
{{ d.[0] }} 去索引对应的值
{{ d.name.[0].hobby }} 还可以这样一直点下去
3.针对函数名模板语法传值之后会自动加括号执行将返回值渲染到页面上
4.针对类名和对象名模板语法传值之后都会先加括号调 类名():返回一个对象的内存地址 对象名(): 返回__call__方法
类名加括号会产生对象
对象加括号不符合正常的调用方式 还是对象本身
但是会触发产生该对象类中的__call__方法
一般是对象点方法名这么调用
######django模板语法不支持函数传参 当需要引用变量名的时候使用双大括号 {{}}
{{}} # 跟变量名相关
{%%} # 跟功能逻辑相关 for if
模板语法值过滤器
# 相当于python的内置函数
{#<p>过滤器:(|) 将管道符左边的数据当做第一个参数传入过滤器中 如果需要第二个参数 则名称后冒号</p>#}
<p>统计长度:{{ l|length }}</p>
<p>加法运算:{{ i|add:123 }}</p>
<p>默认值:{{ b|default:'布尔值为False' }}</p> #判断b是否是true or false
<p>时间格式:{{ ctime|date:'Y-m-d H:i:s' }}</p> #格式'Y-m-d H:i:s'
<p>截取字符(包含三个点的位置):{{ ss|truncatechars:10 }}</p> 比如前端显示name...
<p>截取单词(不包含三个点的位置):{{ ss|truncatewords:3 }}</p> 根据空格分隔单词
<p>文件大小:{{ file_size|filesizeformat }}</p> 转成 k kb m等好看的格式
<p>转义:{{ s1|safe }}</p> #后端写了一个html代码 s1='<h1>uzi yyds wow!!!</h1>' 前端使用safe就能显示了 不然他会<h1>uzi yyds wow!!!</h1>这么显示 原封不动当成字符串展示
#加这个的目的是为了防止恶意脚本攻击也叫xss攻击
后端也可以转义
from django.utils.safestring import mark_safe #导入模块
s2 = "<script>alert(123)</script>"
res = mark_safe(s2)
模板语法值标签
<p>标签:其实就是流程控制 if判断 for循环</p>
{% for foo in s %}
{% if forloop.first %} #第一次循环执行这个
<p>这是第一次循环</p>
{% elif forloop.last %} #最后一次循环执行这个
<p>这是最后一次</p>
{% else %}
<p>继续!!!</p>
{% endif %}
{% empty %}
<p>传递过来的数据是空的</p>
{% endfor %}
forloop 里面的参数
count0 从索引o开始
count 从索引1开始
revcounter 倒序 一直到索引1
revcounter0 倒序 一直到索引0
first 第一个为true 其他为false
last 最后一个为true 其他为false