视图层,模板层
一、视图层(view)
视图函数,本质上就是一个python函数,他接受web请求并返回响应。响应内容可以是HTML网页、重定向、404错误等任何东西,但本质都是返回一个HttpResponse对象。视图函数约定俗成写在view.py文件内
二、请求对象-HttpRequest
request对象 部分常用属性
当一个页面被请求时, django将请求报文中的请求行、首部信息、内容主题封装成HttpRequest类中的属性 。
Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。
1. request.method #方式,返回的是纯大写的字符串。
2. request.GET #获取用户提交的get请求数据,返回的是列表套对象。
3. request.GET.get() #获取列表中的最后一个
4. request.GET.getlist() #获取列表类型的数据
5. request.POST #获取用户提交的post请求数据
6. request.POST.get() #获取列表中的最后一个
7. request.POST.getlist() #获取列表类型的数据
8. request.FILES #包含所有的上传文件信息。
注意:FILES 只有在请求的方法为POST 且提交的from表单带有enctype="multipart/form-data"
的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。
三、响应对象-HttpResponse
响应形式多种多样,可以是HTML网页、重定向、404错误等任何东西,但本质都是返回一个HttpResponse对象。具体的说响应对象主要有三种形式:HttpResponse、render、redirect
3-1. HttpResponse()
HttpResponse()括号内直接跟一个具体的字符串作为响应体。 即返回字符串
3-2. render()
render(request,template_name,[context])
参数:
- request:用于生成响应的请求对象。
- template_name:要使用的模板名称。
- context:添加到模板上下文的一个字典。默认空字典,如果字典中某个值是可调用的,视图将在渲染模板前调用它。
render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
3-3. redirect()
传递要重定向的一个硬编码的URL,即本地的URL文件
def my_view(request):
...
return redirect('some/url')
也可以是一个完整的URL:
def my_view(request):
...
return redirect('http://www.baidu.com')
四、JsonResponse
向前端返回一个json格式字符串的两种方式
# 第一种方式
import json
def my_view(request):
data=['xxx','yyy']
return HttpResponse(json.dumps(data))
# 第二种方式
from django.http import JsonResponse
def my_view(request):
data = ['xxx', 'yyy']
return JsonResponse(data1,safe=False)
# 默认safe=True代表 只能序列化字典,safe=False代表可以序列化其他数据类型
五、FBV与CBV
FBV基于函数的视图(Function base view)
CBV是基于类的视图(Class base view)
# FBV
# FBV视图层书写方式
def login(request):
print('我是login函数')
return render(request,'login.html')
# FBV路由层的书写
url(r'^index/',views.index),
# CBV
# CBV视图层书写方式
from django.views import View
class MyLogin(View):
def get(self,request):
print('我是MyLogin里面的get方法')
return render(request,'login.html')
def post(self,request):
print('我是MyLogin里面的post方法')
return HttpResponse('post')
# CBV路由层的书写
url(r'^login/',views.MyLogin.as_view())
六、 给CBV加装饰器
# 第一种方法:直接书写
class MyLogin(View):
@outter # 1.直接写
def get(self,request):
print('我是MyLogin里面的get方法')
return render(request,'login.html')
@outter # 1.直接写
def post(self,request):
print('我是MyLogin里面的post方法')
time.sleep(1)
return HttpResponse('post')
# 第二种使用内置函数,推荐方法
from django.utils.decorators import method_decorator
# 1-1. 内置函数也可以在外面写,并且可以指定给谁装
@method_decorator(outter,name='post')
class MyLogin(View):
@method_decorator(outter) # 1-2. 推荐写法
def get(self,request):
print('我是MyLogin里面的get方法')
return render(request,'login.html')
def post(self,request):
print('我是MyLogin里面的post方法')
time.sleep(1)
return HttpResponse('post')
# 第三种内置函数联合重写dispatch方法
from django.utils.decorators import method_decorator
class MyLogin(View):
@method_decorator(outter)
def dispatch(self, request, *args, **kwargs):
# 如果你想在视图函数执行之前 做一些操作 你可以在你的CBV中定义dispatch方法来拦截
return super().dispatch(request,*args,**kwargs)
def get(self,request):
print('我是MyLogin里面的get方法')
return render(request,'login.html')
def post(self,request):
print('我是MyLogin里面的post方法')
time.sleep(1)
return HttpResponse('post')
----------------------------------------------------------
一、模板层(template)
存放在template文件夹下的html文件称之为模板文件,利用模板语法可以在html中展示动态数据,简单来说Django的模板=HTML代码+模板语法
二、模板语法之注释
{# this won't be rendered #} 单行注释
注释多行使用comment标签
三、模板语法之变量
在django模板中遍历复杂数据结构的关键是句点字符,语法:{{ 变量名 }}。变量类似于python中的变量。
变量的命名包括任何字母数字以及下划线("_")的组合。点(".")也有可能会在变量名中出现,不过它有特殊的含义。注意:最重要的是,变量名称中不能有空格或标点符号。
views.py:
name='abc'
age=18
li=[1,2,'3','4']
dic={'name':'abc','age':18,''li:[1,2,4]}
def test(): #函数
print('abc')
return 'abchahahah'
class Person():
def __init__(self,name,age)
self.name=name
self.age=age
def get_name(self):
return self.name
@classmethod
def cls_test(cls):
return 'cls'
@staticmethod
def static_test():
return 'static'
---------
# 模板里不支持带参数
def get_name_cs(self,ttt):
return self.name
----------
xxx=Person('xxx',18)
yyy=Person('yyy',28)
person_list=[xxx,yyy]
html:
相当于print了该变量
<p>字符串:{{ name }}</p>
<p>数字:{{ age }}</p>
<p>列表:{{ li }}</p>
<p>元祖:{{ tu }}</p>
<p>字典:{{ dic }}</p>
<p>函数:{{ test }}</p> {#只写函数名:相当于函数名(),返回函数执行结果#}
<p>对象:{{ xxx }}</p> {#对象内存地址#}
深度查询:
<p>列表第1个值:{{ ll.0 }}</p>
<p>列表第4个值:{{ ll.3 }}</p>
<p>字典取值:{{ dic.name }}</p>
<p>字典取列表值:{{ dic.li }}</p>
<p>对象取数据属性:{{ xxx.name }}</p>
<p>对象取绑定给对象的函数属性:{{ xxx.get_name }}</p>
<p>对象取绑定给类的函数属性:{{ xxx.cls_test }}</p>
<p>对象取静态方法:{{ xxx.static_test }}</p>
四、模板语法之标签
一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 语法为{% tagname %}
模板语法的取值 只有一种方式 统一采用句点符 (.)
4-1. for循环
# 遍历每一个元素
{% for person in person_list %}
<p>{{ person }}</p>
{% end for%}
# 遍历一个字典:
{% for k,v in dic.items %}
<p>{{ k }}:{{ v }}</p>
下面是Django为for标签内置的一些属性,可以当作变量一样使用{{ }}
在模版中使用。
- forloop.counter:循环的当前索引值,从1开始计数;常用于生成一个表格或者列表的序号
- forloop.counter0:循环的当前索引值,从0开始计数;
- forloop.revcounter: 循环结束的次数(从1开始)
- forloop.revcounter0 循环结束的次数(从0开始)
- forloop.first:判断当前是否循环的第一次,是的话,该变量的值为True。我们经常要为第一行加点特殊的对待,就用得上这个判断了,结合if。
- forloop.last:如果这是最后一次循环,则为真
- forloop.parentloop:对于嵌套循环,返回父循环所在的循环次数
4-2. for...empty
for标签带有一个可选的{% empty %}
从句,在给出的组是空的或者没有被找到时执行的操作
注:循环的对象是空,才会走到empty,而不是对象里面的东西为空
{% for person in person_list %}
<p>{{ person.name }}</p>
{% empty %}
<p>sorry,no person here</p>
{% endfor %}
4-3. if判断
{% if %}
会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
{% if num > 100 or num < 0 %}
<p>无效</p>
{% elif num > 80 and num < 100 %}
<p>优秀</p>
{% else %}
<p>良好</p>
{% endif %}
注:在if标签中使用括号是错误的语法,这点不同于Pythonif语句支持 ,优先级可以使用if嵌套。if支持and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
4-4. 标签实例
# for if联合使用
{% for foo in l %}
{% if forloop.first %}
<p>这是我的第一次</p>
{% elif forloop.last %}
<p>这是最后一次了啊</p>
{% else %}
<p>{{ foo }}</p>
{% endif %}
{% empty %}
<p>当for循环的对象是空的时候会走</p>
{% endfor %}
# 模板语法的取值 只有一种方式 统一采用句点符 (.)
comp_dic = {'username':'jason','hobby':['read','study',['run','rap',{'age':18}]]}
# 获取字典嵌套中的age
<p>{{ comp_dic.hobby.2.2.age }}</p>
五、模板语法之过滤器
在Django的模板语言中,通过使用过滤器来改变变量的显示。过滤器的语法: {{ value|filter_name:参数 }}
注意事项:
- 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
- 过滤器可以接受参数,只能接受一个参数
- 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
- '|'左右没有空格
常用过滤器
1. default
<!-- 如果变量是false或者为空,则使用给定的默认值。-->
{{ value|default:'nothing'}}
2. length
<!-- 返回值的长度,对字符串和列表都起作用-->
value=[1,2,3,4]
{{ value|length}} 输出是4
3. filesizeformat
<!-- 将值格式化成'人类可读的'文件尺寸。-->
{{1024|filesizeformat}} 输出为1kb
4. safe
<!-- Django模板为了安全默认会对HTML标签和js等语法标签进行转义,有时候我们不希望这些元素被转义,可以通过设置过滤器。-->
script="'<script>alert(111)</script>"
{{ script|safe }}
# 补充:后端也可以利用模块取消转义
from django.utils.safestring import mark_safe
sss2 = "<h2>我的h2标签</h2>"
res = mark_safe(sss2)
5.slice
<!-- 切片,不支持负数 -->
{{ name|slice:'0:3:3' }}
6.truncatechars
<!-- 如果字符串多余指定字符数量,多余会被截断,替换成("...")结尾。 -->
{{ value|truncatechars:9}}
7.truncatewords
<!-- 在一定数量的字后截断字符串。-->
{{ value|truncatewords:9}}
六、自定义标签和过滤器
6-1. 自定义前置准备
-
在应用名(app文件夹)下新建一个
templatetags
包(名字固定),与views.py、models.py等文件在同一目录 -
在该文件夹内 新建一个任意名称的.py文件, 如:
my_tags.py
-
在该.py文件中 必须先写下面两句代码
from django.template import Library register = Library()
6-2. 自定义过滤器
自定义过滤器实际就是一个带有一个或两个参数的python函数
注:函数的第一个参数是要过滤的对象,第二个是自定义参数,函数一共只能有两个参数。
- 变量的值:不一定是字符串形式
- 可以有一个初始值,或者不需要这个参数
# 自定义过滤器 跟默认的过滤器一样 最多只能接受两个参数
# 利用register.filter注册并给该过滤器起别名
@register.filter(name='baby')
def index(a,b):
return a + b
# 自定义过滤器的使用
# 在要使用自定义过滤器的模板文件中导入创建的py文件。语法:{% load 文件名 %}
{% load mytag %}
{{ 1|baby:1 }}
{{ 1|baby:100 }}
# 自定义的过滤器可以在逻辑语句使用 而自定义的标签不可以
{% if mytag '1' '2' '3' '4' %}
<p>有值</p>
{% else %}
<p>无值</p>
{% endif %}#
6-3. 自定义标签
除了装饰器,其它步骤与自定义过滤器相似。
过滤器只能有两个参数,自定义标签可以传多个值,空格传值。
注:过滤器可以用在if判断中,标签不能
# 自定义标签 可以接受任意多个参数
# 利用register.simple_tag()注册并给该标签起别名
@register.simple_tag(name='mytag')
def mytag(a,b,c,d):
return '%s?%s?%s?%s'%(a,b,c,d)
# 自定义标签的使用 可以接受多个参数 参数与参数之间必须空格隔开
{% load mytag %}
{% mytag 'a' 'b' 'c' 'd' %}
6-4. 自定义inclusion_tag
"""
是一个函数 能够接受外界传入的参数 然后传递给一个html页面
页面上获取数据 渲染 完成之后
将渲染好的页面 放到调用inclusion_tag的地方
"""
# 自定义inclusion_tag
@register.inclusion_tag('mytag.html',name='xxx')
def index666(n):
l = []
for i in range(n):
l.append('第%s项'%i)
return locals() # 将l直接传递给mytag.html页面
# 自定义inclusion_tag的使用 当你需要使用一些页面组件的时候 并且该页面组件需要参数才能够正常渲染 你可以考虑使用inclusion_tag</p>
{% load mytag %}
{% xxx 5 %}
七、模板的继承
模版继承可以创建一个基本的“骨架”模版,它包含站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks
注意:
- 模板上的block区域越多 页面的扩展性越强,一个模板页面最好有三块区域:css区域、html代码区域、js区域 html区域可以设置多个block。有了这三块区域,就能够实现每一个页面都有自己独立的css和js代码
- 不能在一个模板中定义多个相同名字的block标签
- 如果在模板中使用
{% extends %}
标签,它必须是模板中的第一个标签
# 子模板login.html继承index.html文件模板,全部继承的情况下无法修改内容
# 即login.html中只需要写一句代码
{% extends 'home.html' %}
# 如果子模板需要修改部分,就需要用到 block
# 母模板 index.html
...
<body>
<div id="sidebar">
# 划定这块区域可以修改,并取别名sidebar
{% block sidebar %}
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
# 划定这块区域可以修改,并取别名content
{% block content %}{% endblock %}
</div>
# 子模板 login.html
{% extends 'home.html' %}
# 使用block,pycharm会自动提示有哪些区域
{% block sidebar %}
...修改内容
</style>
{% endblock %}
{% block content %}
...修改内容
{% endblock %}
八、模板的导入
用简单的模板语句解决了重复组件的代码冗余
语法:{% include '模板名称' %}
# 做好注册前提准备,简单的代码可以直接运行imp路径
# imp.html文件内容
{% include 'fr.html' %}
# fr.html文件内容
<p>这是一个特别好看的form表单</p>