内容概览
- 网页伪静态
- 视图层
- 视图函数的返回值
- 视图函数返回JSON格式数据
- form表单携带文件数据
- FBV与CBV
- CBV源码分析
- 模板层
- 模板语法传值
- 模板语法传值的范围
- 模板语法过滤器
- 模板语法标签
- 自定义标签函数、过滤器、inclusion_tag
- 模板的继承
- 模板的导入
网页伪静态
将动态网页伪装成静态网页,提升网页被搜索引擎收录的概率
表现形式就是使网址看上起像一个具体的文件路径
urls:
# 将路由写成文件路径的样式
urlpatterns=[
path('home.html', views.home)
]
视图层
视图函数的返回值
如果视图函数不写返回值会直接报错
视图函数必须返回一个HttpResponse对象
render与redirect其实底层也是返回的HttpResponse对象
render:
redirect返回的是一个继承了HttpResponse的类的对象:
视图返回JSON格式数据
想要返回JSON格式数据可以直接使用json模块序列化
def fn(request):
import json
user_dict = {'name': 'jason', 'age': 28}
json_str = json.dumps(user_dict, ensure_ascii=False) # 如果数据中有中文,需要设置ensure_ascii属性确保中文正常显示
return HttpResponse(json_str)
但是django提供了一种更简便的方式
def fn(request):
from django.http import JsonResponse
user_dict = {'name': 'jason', 'age': 28}
return JsonResponse(user_dict)
JsonResponse源码:
class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
if safe and not isinstance(data, dict):
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None:
json_dumps_params = {} # 如果没有传值,则设置为空字典
kwargs.setdefault('content_type', 'application/json')
data = json.dumps(data, cls=encoder, **json_dumps_params) # 将json_dumps_params拆解为关键字参数
super().__init__(content=data, **kwargs)
通过查看源码可以知道,使用JsonResponse想要使中文正常显示,返回值需要这样写:
return JsonResponse(data, json_dumps_params={ensure_ascii:False})
# 如果想要序列化非字典类型的数据还需要将参数safe设定为False
form表单携带文件数据
想要使后端接收到form表单发送的文件数据,需要下述条件:
from表单的method属性必须为post;enctype属性值必须是multipart/form-data
<form method='post' enctype='multipart/form-data'>
<input class='file' name='file'>
<input class='submit' value='提交'>
</form>
后端使用request.FILES接收
def fn(request):
f = request.FILES.get('file')
print(f.name) # 可以用.name获取标签的name属性的值
FBV与CBV
FBV:基于函数的视图
"""urls"""
path('func/', views.func)
"""views"""
def func(request):
return HttpResponse()
CBV:基于类的视图
"""urls"""
path('func/',views.MyView.as_view())
# path('路由',views.类名.内置的方法)
"""views"""
from django import views
class MyView(views.View):
def get(self, request):
return HttpResponse('get')
def post(self, requese):
return HttpResponse('post')
CBV会根据请求方式的不同匹配类中定义的方法并自动执行
CBV源码分析
源码分析入口:
path('func/', views.MyView.as_view())
# 在程序运行时,会直接调用as_view()方法
as_view:
返回了view方法名,那么路由匹配就可以看做是:
path('func/', views.MyView.view)
访问func/触发view执行,接下来就看view中发生了什么
def view(request, *args, **kwargs):
self = cls(**initkwargs) # cls是之前自动传入的类
if hasattr(self, 'get') and not hasattr(self, 'head'): # hasattr反射函数,通过字符串判断类里是否有get属性或方法
self.head = self.get
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs) #相当于又用类调用了一个方法
dispatch:
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
# http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] 如果请求方式是这常见的8个,那么就可以直接调用
handler = getattr(self, request.method.lower(), self.http_method_not_allowed) # request.method获取请求方式,lower转成小写然后获取
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) # return 调用返回值
模板层
模板语法传值
# 方式一:指定数据
return render(request, 'modal.html', {'data': data})
"""指定数据传参,不浪费资源;但是文件数量太多会很麻烦"""
# 方式而:关键字locals()
return render(request, 'madal.html', locals())
"""将整个局部名称空间中的名字全部传入,简单快捷;但是如果只需要一条数据而传了很多,那么造成了资源浪费"""
模板语法传值的范围
基本数据类型能够直接传递使用:
int、float、str、bool、list、tuple、set、dict
函数名的传递会自动加括号调用,并将返回值展示到html页面上;模板语法只支持无参函数,对于有参函数则不会执行和展示
python:
def func1(request):
def fn1():
return 'from fn1'
def fn2(a):
return 'from fn2'
return render(request, 'myhtml01.html', locals())
html:
<p>{{ fn1 }}</p>
<p>{{ fn2 }}</p>
浏览器:
类名的传递也会自动加括号产生对象并将对象展示到页面上,而对象的传递则可直接使用
python:
def func1(request):
class cls1(object):
pass
obj1 = cls1()
return render(request, 'myhtml01.html', locals())
html:
<p>{{ cls1 }}</p>
<p>{{ obj1 }}</p>
浏览器:
模板语法过滤器(类似于python内置函数)
管道符|与冒号:左右不能有空格
1. 统计长度
<p>{{ s|lenght }}</p> 统计s中值的数量
2. 加法运算
<p> {{ i|add:666 }} </p> 将i中的值与666相加,可以是算数运算,也可以是字符串拼接;如果都报错则返回空字符串
3. 日期转换
<p>{{ new_date|date:'Y-m-d H:i:s' }}</p> 将传入数据转换为格式化日期
4. 文件大小
<p>{{ file_size|filesizeformat }}</p> 将传入数据转换为合适的单位展示,最大支持PB
5. 数据切片
<p>{{ l1|slice:'0:2'}}</p> 将容器数据类型切片取值,遵循左闭右开原则
6. 字符截取
<p>{{ s1|truncatechars:5 }}</p> 截取指定个数字符,如果数据没有被截取完,那么截取的最后一个字符会替换成...
<p>{{ s1|truncatewords:2 }}</p> 按照空格截取指定个数数据,如果数据没有被截取完,那么在最后会添加...
7. 语法转义
<p>{{ scr|safe }}</p> 传入的参数默认全都是字符串传入,使用语法转义后就可以从后端写html的代码,例如:
scr = '<script>alert(123)</script> <h1>Title</h1>'
django模板语法中的符号就只有{{}}与{%%}两个
在需要使用数据的时候使用{{}}
在需要使用方法的时候使用{%%}
模板语法标签(类似于流程控制)
<!--if分支-->
{% if 条件1 %} 条件一般是模板语法传过来的数据,已经使用了{%%}符号就直接写名字即可
条件1成立执行的代码
{% elif 条件2 %}
条件2成立执行的代码
{% else %}
上述条件都不成立执行的代码
{% endif %} 结束符
<!--for循环-->
{% for i in s %}
{% if forloop.first %}
<p>判断是否为第一次循环</p>
{% endif %}
{% if forloop.counter == 3 %}
<p>counter是当前循环次数,从1开始;counter0从0开始</p>
{% endif %}
{% if forloop.revcounter == 1 %}
<p>revcounter是倒数,从1开始;revcounter0从0开始</p>
{% endif %}
{% if forloop.last %}
<p>判断是否为最后一次循环</p>
{% endif %}
{% empty %}
<p>传入循环的数据为空</p>
{% endfor %}
自定义标签函数\过滤器\inclusion_tag
如果想要使用自定义,有以下条件:
- 在应用下创建一个名为templatetags文件夹
- 在文件夹内创建一个py文件
- 在py文件内编写自定义相关代码
- py文件中输入代码
from django.template import Library register = Library()
- 在html页面使用前需要先加载文件
{% load '创建的py文件' %}
- 自定义过滤器
@register.filter(name='myfilter')
def my_add(a, b):
return a + b
# 最多只支持两个参数传入
- 自定义标签函数
@register.simple_tag(name='mt')
def fn(a, b, c, d):
return a + b + c + d
# 能够使用多个参数
# 使用方式:{% fn 1 2 3 4 %}
- 自定义inclusion_tag
@register.inclusion_tag(filename='myhtml.html')
def fn2(n):
num_list = []
for i in range(n):
html.append(f'第{i}页')
return locals()
myhtml:
<ul>
<% for i in num_list %>
<li>{{ i }}</li>
<% forend %>
</ul>
提前写好一个动态网页,后续调用函数名相当于插入了一段html代码
使用方式:
{% fn2 5 %}
模板的继承
使用{% extends html文件名 %}就相当于是复制了指定html文件的代码过来
那么如果想要修改其中部分内容,则需要提前在母版中划分哪些部分需要修改
母版:
{% block 名字 %}
待修改的模板内容
{% endblock %}
子版:
{% extends '母版名' %}
{% block 名字 %}
修改的模板内容
{{ block.super }} <!--使用母版中的内容,类似于python中类super方法-->
{% endblock %}
一般情况下母版中至少应该有三个区域可更改:css、模板内容、script;使得扩展性更高
模板的导入
将html页面当做模块的形式导入使用
{% include 'html文件名' %}
类似于自定义inclusion_tag;区别在于模板导入的是一个静态的