django的视图层和模版层
视图层
视图函数的返回值问题
当视图函数不返回HttpResponse的情况
# 1.在urls.py开设一个路由
path('test/',views.test)
# 2.在views.py写test视图函数并返回一个None
def test(request):
return None
会报错,意思就是没有返回一个HttpResponse对象
查看三板斧HttpResponse、render、redirect返回的对象
通过查询三板斧HttpResponse、render、redirect源码分析,它们最终都直接或间接的返回了一个response对象
- HttpResponse
# 源码
class HttpResponse(HttpResponseBase):
...
# 视图函数
def test(request):
return HttpResponse('xxx')
在视图函数test,返回的是一个HttpResponse对象:HttpResponse类加括号实例化一个对象
- render
# render源码
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
由源码可以看出,render本质上返回的是一个HttpResponse对象
- redirect
可以看出redirect方法返回的是如图所指的类实例化的对象
点进去查看这两个类,发现它们都继承了HttpResponseRedirectBase父类
查看HttpResponseRedirectBase类,发现继承于HttpResponse类
所以,redirect本质也是返回的HttpResponse对象
总结
视图函数必须返回一个HttpResponse对象
视图函数返回json格式数据
用json模块
import json
def test1(request):
info_dict={'name':'jason','age':18,'hobby':'打篮球,踢足球'}
json_info=json.dumps(info_dict,ensure_ascii=False)
return HttpResponse(json_info)
ensure_ascii=False
显示中文,不设置此参数就会以二进制字节展示
用django自带JsonResponse模块
from django.http import JsonResponse
def test1(request):
info_dict={'name':'jason','age':18,'hobby':'打篮球,踢足球'}
return JsonResponse(info_dict)
默认也是将不显示中文,通过查看源码可知,HttpResponse也是利用json进行序列化,并继承并重写了json.JsonEncoder类,它想要传dumps括号后面的参数可以通过json_dumps_params = {}
的形式,将关键字参数按k:v的形式传进去。
如果我们想在页面显示中文,写如下代码就行
return JsonResponse(info_dict,json_dumps_params={'ensure_ascii':False})
序列化非字典类型数据
当序列化非字典类型页面会报错
只需要指定safe参数为False就行了
from django.http import JsonResponse
def test1(request):
info_dict={'name':'jason','age':18,'hobby':'打篮球,踢足球'}
a_list=[1,2,3,'打篮球']
return JsonResponse(a_list,safe=False,json_dumps_params={'ensure_ascii':False})
form表单携带文件数据
form表单需要具备的条件
- method属性值必须是post
- enctype属性值必须是multipart/form-data
后端获取文件数据的操作
- request.FILES
代码演示
# 1. 路由层开设路由
path('file/',views.file)
# 2. 视图函数写file函数
def file(request):
if request.method=='POST':
file_b=request.FILES.get('file')
with open('file_a','wb') as f: # 指定文件写入的路径
for line in file_b:
f.write(line)
return render(request,'file.html')
# 3.前端页面
<form action="" method="post" enctype="multipart/form-data">
<p><input type="file" name="file"></p>
<p><input type="submit" value="提交"></p>
</form>
</body>
FBV与CBV
FBV:基于函数的视图
def index(request):
return HttpResponse()
path('index/', views.index)
CBV:基于类的视图
用不同的函数针对不同的HTTP方法处理,而不是通过if判断,提高代码的可读性
# 1. 路由层开设路由
path('view/',views.View.as_view())
# 2. 写类视图
from django import views
class view(views.View):
def get(self,request):
return HttpResponse("我是CBV的get方法")
def post(self,request):
return HttpResponse("我是CBV的post方法")
CBV会自动根据请求方法的不同匹配类中定义的方法并自动执行
CBV源码分析(重要)
源码分析入口
path('view/',views.View.as_view())
- 绑定给类的as_view方法
- CBV路由匹配本质:跟FBV是一致的
# 等价于
path('view/',views.view)
- 访问func触发view执行
通过View类实例化产生对象,在通过对象点dispatch方法
- 研究dispatch方法
调用父类的dispatch方法后,将用户的请求方式转为小写,通过反射判断请求在不在类中方法,在就执行对应请求函数,不在则无法正常显示页面,日志会打印:Method Not Allowed: /view/
涉及到对象点名字,一定要确定对象是谁,再确定查找顺序
模版层
模版语法传值
- 指名道姓:指名道姓传参,不浪费资源。
return render(request, 'modal.html', {'name':name})
- 关键字locals():将整个局部名称空间的名字全部传入,简单快捷。
return render(request,'modal.html',locals())
模版语法传值的范围
-
基本数据类型直接传递使用
-
函数名的传递会自动加括号执行并将返回值展示到页面上
-
类名的传递也会自动加括号产生对象并展示到页面上
-
对象的传递则直接使用即可
-
django的模版语法在操作容器类型的时候只允许使用句点符
注意函数如果有参数则不会执行也不会展示,模版语法不支持有参函数
# urls.py开设路由
path('test2/',views.test2)
#views.py写逻辑代码
def aaa():
return 'aaa'
class Person:
def __init__(self):
pass
def test2(request):
p=Person # 类
p1=Person() # 对象
a=aaa # 函数名
return render(request,'test2.html',locals())
# html页面
<body>
<h3>{{ p }}</h3>
<h3>{{ p1 }}</h3>
<h3>{{ a }}</h3>
</body>
浏览器输入url
模版语法过滤器(类似于python内置函数)
import datetime
def filter1(request):
a='hello,world!'
b=10
c=datetime.datetime.today()
d=23232323232
e=[1,2,3,4,5,6]
f='my name is jason'
css_tag='<i>你好</i>'
script_tag='<script>alert(123)</script>'
# 语法转义第二种方式
from django.utils.safestring import mark_safe
res=mark_safe('<script>alert(333)</script>')
return render(request,'filter.html',locals())
<body>
<h3>统计字符长度{{ a|length }}</h3>
<h3>加法运算:{{ b|add:100 }}</h3>
<h3>时间日期转换{{ c|date:'Y-m-d H:i:s' }}</h3>
<h3>字符串拼接{{ a|add:'hello' }}</h3>
<h3>文件大小{{ d|filesizeformat }}</h3>
<h3>数据切片{{ e|slice:'0:10' }}</h3>
<h3>字符截取{{ f|truncatechars:4 }}</h3> // ...也算一个字符
<h3>单词截取{{ f|truncatewords:4}}</h3>
<h3>语法转义:{{ css_tag|safe }}</h3>
<h3>语法转义{{ script_tag|safe }}</h3>
<h3>语法转义的第二种方式:{{ res }}</h3>
</body>
django模版语法中的符号就两个,一个{{}}
,一个{%%}
- 需要使用数据的时候:{
- 需要使用方法的时候:
模版语法标签(类似于python流程控制)
if语句
<body>
{% if 1 %}
<h1>我是if</h1>
{% elif 1 %}
<h1>我是elif</h1>
{% else %}
<h>我是else</h>
{% endif %}
</body>
for语句
def test3(request):
a=False
b=True
s='helloworld'
d=''
return render(request,'test3.html',locals())
<body>
{% for i in s %}
{% if forloop.first %}
<p>first</p>
{% elif forloop.last %}
<p>last</p>
{% else %}
<p>{{ i }}</p>
{% endif %}
<p>你给我的是空,我怎么循环</p>
{% endfor %}
</body>
自定义标签函数、过滤器、inclusion_tag
如果想自定义,必须先做一下三件事
- 在应用下创建一个名为templatetags的文件夹
- 在该文件夹创建任意名称的py文件
- 在该py文件内编写自定义相关代码
自定义过滤器
- 在templatetags文件夹创建一个mytag的py文件
from django.template import Library
register=Library()
@register.filter(name='myfilter')
def add(a,b):
return a+b
- 在前端页面需要先导入mytag
{% load mytag %}
<h2>{{ d|myfilter:100 }}</h2>
自定义标签函数
@register.simple_tag(name='mt')
def func(a,b,c,d):
return a+b+c+d
<h2>{% mt 1 2 3 4 %}</h2>
自定义inclusion_tag
- 在mytag文件夹
@register.inclusion_tag(filename='inclu.html')
def index(n):
html=[]
for i in range(n):
html.append(f'第{i}页')
return locals()
- 创建一个名为
inclu
的html文件
{% for i in html %}
<ul>
<li>{{ i }}</li>
</ul>
{% endfor %}
- 在需要导入的html页面导入
{% load mytag %}
{% index 10 %} <!-- 10为显示数量可随意设定-->
模版的继承
{% extends 'html文件名' %}
{% block 名字 %}
模板内容
{% endblock %}
{% block 名字 %}
子板内容
{% endblock %}
一般情况下母板中至少应该有三个区域使得扩展性更高:css、content、js
{% block css %}
# css代码区
{% endblock %}
{% block content %}
# 内容区
{% endblock %}
{% block js %}
# js代码区
{% endblock %}
模版的导入
将html页面的某个部分当做模块的形式导入使用
{% include 'menu.html' %}
网页伪装态
将动态网页伪装成静态网页,从而提升网页被搜索引擎收录的概率,表现形式就是网站看着像一个具体的文件路径
path('index.html',view.index)