Django视图层和模板层
视图层
网页伪静态(了解)
1.从URL结构以及页面名称看,伪静态和静态页面是一样的。伪静态的页面后缀可以是html,htm或者是目录格式。
2.伪静态只是改变了URL的表现形式,实际上还是动态页面。
3.静态页面可以节省服务器资源,而伪静态严格说是增加服务器资源消耗的。
4.在SEO方面,伪静态和静态页面的功能是相同的,但是伪静态本质上还是动态页面,所以消耗资源是和动态页面一样的,而且因为Rewrite服务器还需要消耗额外的资源。
# 通过写入网页的后缀名将动态网页伪装成静态网页,让服务器误以为这个网页不会经常改变,从而提升网页被搜索引擎收录的概率。表现形式就是网址看着像是一个具体的文件路径
path('index.html',views.index)
视图函数的返回值
'''视图函数必须返回一个HttpResponse对象'''
代码验证一下:
def func(request):
pass
报错信息看下图
通过查看HttpResponse源码发现HttpResponse是个类
class HttpResponse(HttpResponseBase):
pass
那么此时就有一个疑问,同样是django三板斧,视图函数返回值为什么只能返回HttpResponse,而不是另外两个render和redirect呢?
先看看render的源码:
def render(request):
return HttpResponse(content, content_type, status)
# 通过查看源码发现 render是一个函数,但是!它的返回值是HttpResponse。函数名加括号执行优先级最高,由此可推出render返回值也是一个HttpResponse对象
那么再看看redirect的源码来验证上面的结论是否正确
def redirect(to, *args, permanent=False, **kwargs):
redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs))
# 此时只能看出redirect是一个函数,再去查看它的返回值源码
class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
status_code = 301
# 再去查看返回值继承的类
class HttpResponseRedirectBase(HttpResponse):
pass
'''查看返回值继承的类发现,redirect的返回值继承的元类是HttpResponse类,那么由此可以推导出redirect的返回值返回的也是HttpResponse对象'''
jsonResponse方法
视图函数返回json格式数据
# 使用import json模块写代码
def func(request):
d1 = {'name': 'summer哈哈哈', 'age': 18}
json_str = json.dumps(d1,ensure_ascii=False)
return HttpResponse(json_str)
运行结果:{"name": "summer哈哈哈", "age": 18}
# 使用django封装的模块JsonResponse
from django.http import JsonResponse
def func(request):
d1 = {'name': 'summer哈哈哈', 'age': 18}
return JsonResponse(d1,json_dumps_params={'ensure_ascii':False})
运行结果:{"name": "summer哈哈哈", "age": 18}
# 通过查看JsonResponse源码推导出 json_dumps_params可以接收ensure_ascii:False
推导过程:
1.JsonResponse继承了HttpResponse ,也就是当JsonResponse加括号的时候就是实例化了一个对象,对象的第一个参数是self是自己,第二个参数data是括号内是数据,也就是上述字典
2.直接看data赋值符号的右边,是json.dumps把data数据转为json格式,括号内的参数有一个**json_dumps_params
3.在__init__括号内有一个参数json_dumps_params=None,然后再看下面的if判断 if json_dumps_params is None:,json_dumps_params = {}。由此可以推导出,**json_dumps_params是可以接收这种形式的参数ensure_ascii:False
# json格式化非字典类型数据
def func(request):
l1 = [1,1,1,1,12,2,2,2]
return JsonResponse(l1,safe=False)
# 通过报错提示,我们可以直接看到其他格式的编写参数
form表单携带文件数据
form表单想要携带文件数据的话,前端必须具备两个条件
1.method属性必须是post
2.enctype属性值必须是multipart/form-data
# form表单默认的是 enctype="application/x-www-form-urlencoded" 这种模式不支持携带文件
后端获取文件:
request.FILES
代码实操:
def userfile(request):
if request.method == 'POST':
# print('request.POST',request.POST)
print('request.FILES',request.FILES)
file_obj = request.FILES.get('file') # 如果有多个文件就用getlist
with open(file_obj.name,'wb')as f:
for line in file_obj:
f.write(line)
没有写enctype="multipart/form-data"
写了enctype="multipart/form-data"
FBV与CBV
在django框架中,视图层中的逻辑即可以使用函数处理也可以使用类进行处理:
FBV(function base views) 就是在视图里使用函数处理请求。
def index(request):
return HttpResponse()
path('index/',views.index)
CBV(class base views) 就是在视图里使用类处理请求。
from django import views
class myView(views.View):
def get(self, request):
return HttpResponse('我是get里面的views')
def post(self, request):
return HttpResponse('我是post里面的views')
path('func/',views.myView.as_view())
CBV会根据请求方式的不同,来匹配类中定义的方法,并自动执行!!!
CBV源码(很重要!!!)
'''CBV根据请求方式的不同匹配不同的方法的底层原理'''
# 第一步:
path('func/',views.myView.as_view())
由于python中的一切皆对象,类点一个名字就相当于对象在点一个名字,这点可以推断as_view不是一个普通的名字,要么是方法要么是功能,而类能点的方法要么是专门绑定给类的方法,要么就是函数,而as_view()没有传参数,由此推断,此方法是专门绑定给类的,类调用就把自身当作第一个参数传进去
1.类/对象查找属性/方法的第一步是先看自身有没有,自身没有!所以查看源码的入口就是 as_view()
2.查看as_view发现,产生这个方法的类是view,而as_view方法是专门给类调用的,那么此时的cls = myView
3 .再看as_view这个方法返回值是view
def as_view():
def view():
return view
那么 path('func/',views.myView.as_view())
也可以写成 path('func/',views.view)
从底层原理上看CBV路由匹配本质:跟FBV是一致的
# 第二步:
1.view这个方法里的self = cls(**initkwargs)就是self = myView()
类名加括号产生的就是这个类的对象,此时的self就是myView的对象
2.查看返回值return self.dispatch(request, *args, **kwargs)
对象在点一个方法
'''此时我们就应该想到,对象点方法的查找顺序,如果对象本身没有这个方法,那么就去产生对象的类里面去找,如果对象的类里面没有这个方法,那么就去继承的类里去找'''
# 第三步:
1.查看dispatch方法,def dispatch(self, request, *args, **kwargs)
对象在调用一个方法的时候传的是对象本身,那么此时的self依旧是myView()
2.查看if判断:
if request.method.lower() in self.http_method_names
# 如果myView()的请求方法在http_method_names这个方法列表内
通过反射将对象的请求小写并赋值给handler,最后返回handler()调用
# 假设是get方法返回的就是get方法的return,post返回的就是post方法的return
'''CBV视图层中,dispatch方法可以说是前端向后端发送请求的调度员,可以根据不同的请求的方式执行视图类中对应的方法'''
# http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
模板层
模板语法传值的两种方式
1.指名道姓的传值:
def func(request):
name = 'jason'
return render(request,'myhtml02',{'name':name})
优点:精确度高,有效利用资源,不过多占用内存
缺点是:如果需要传的值比较庞大的时候,那么需要写很多重复的代码,代码冗余,不符合程序员偷懒特性!!
2.关键字locals传值 将整个名称空间的名字全部传入
def func(request):
name = 'jason'
age = 88
hobby = '吨吨吨'
return render(request,'myhtml02',locals())
优点:传值数据量大的时候,方便快捷,易操作
缺点:当数据量大,但是需要的传值数据就那么一两个的时候 ,占用内存空间
模板语法传值特性
# 模板语法传值是类型范围
python的基本数据类型都可以传值!
ps:python模板语法操作容器类数据的时候只允许使用句点符
# 函数类型传值
def func():
print('哈喽啊,美好的一天')
return '美好的周末'
函数的传值会自动加括号执行,并将返回值展示在页面
ps:模板语法不支持有参函数(不支持也不执行不展示),无法给函数传参
# 类传值
def func(request):
class MyClass(object):
def get_obj(self):
return 'obj'
@classmethod
def get_cls(cls):
return 'cls'
@staticmethod
def get_func(self):
return 'func'
obj = MyClass()
return render(request, 'myhtml02.html', locals())
# 类名的传递会自动加括号产生对象并展示到页面,对象的传递则直接使用即可
即:<p>{{ obj.get_func }}</p> 等
ps:魔法语法会自动判断每个名字类型是否可以加括号调用,可以的话直接调用。类似于callable()
图1:
模板语法之过滤器
# 类似于python的内置函数
模板方法符号:
数据使用 :{{ }}
方法使用: {% %}
<p>统计长度:{{ s|length }}</p>
<p>加法运算:{{ i|add:123 }}、加法运算:{{ s|add:'heiheihei' }}</p>
# <p>日期转换:{{ s|date:'Y-m-d H:i:s' }}</p>
from datetime import datetime
res = datetime.today()
<p>{{ res|date:'Y-m-d H:i:s' }}</p>
<p>文件大小:{{ file_size|filesizeformat }}</p>
file_size = 111111233 # 106.0MB
<p>数据切片:{{ l|slice:'0:10' }}</p>
#
<p>字符截取(三个点算一个):{{ s1|truncatechars:6 }}</p>
<p>单词截取(空格):{{ s1|truncatewords:6 }}</p>
# <p>语法转义:{{ script_tag|safe }}</p>
<p>语法转义:{{ script_tag1|safe }}</p>
from django.utils.safestring import mark_safe
script_tag1 = '<script>alert(666)</script>'
res = mark_safe(script_tag1)
模板语法之标签
# 类似于python中的if判断
{ % if 条件 % }
条件成立执行的代码
{ % elif 条件 % }
条件成立执行的代码
{% else %}
条件不成立执行的代码
{% end if%}
# 类似于python中的for循环 关键字forloop
{ % for i in l%}
{{ forloop }}
{% endfor %}
ps:empty 空 如果是空的话返回empty里面的代码
自定义相关功能
# 自定义标签 ,过滤器,inclusion_tag
如果想自定义 必须先做一下三件事:
1.在应用下创建一个templates_tag文件夹
2.在该文件夹创建任意名称的py文件
3.在该py文件内编写自定义相关代码、
# 自定义过滤器 最多只能有两个参数
from django.template import library
register=Library()
@reginster.filter(name = 'myfilter')
def my_add(a,b):
return a+b
{% load my_tag%}
{{i|myfilter:1}}
# 自定义标签函数 可以用多个参数
@register.simple(name ='mt')
def func(a,b,c,d):
return a+b+c+d
{% mt 1,2,3,4 %}
# inclusion_tag
@register.inclusion_ta(func='it',filename='it.html')
def index(n):
html=[]
for i in range(n):
html.append('第%s页'%i)
return locals()
it.html:
{% for i in html % }
<li>{{i}}</li>
{% endfor %}
调用页面:
{% index 10 %}
{% index 5 %}
模板的继承与导入
继承页面:
{% extends 'home.html' %} # 继承
{% block content %}
修改的内容
{% endblock %}
被继承页面:
{% block content %}
可以修改的内容
{% endblock %}
一般模板中至少有三个区域:css js content
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)