Django-2.视图和模板

Django视图

Django中视图函数,简称视图,相当于一个函数,接受客户端的请求的数据,进行处理,然后在响应给客户端。

http请求产生两个核心对象,分别为HttpRequest(请求)对象,HttpResponse(响应)对象,这两个方法在django.http目录下

HttpRequest属性

在views视图函数中定义的request就是HttpRequest对象,监测可使用isinstance方法来检测

HttpRequest类在django.http.request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def index(request):
print(isinstance(request,HttpRequest))
return HttpResponse('...')


#HttpRequest方法
request.GET.get('key') #如果客户端是GET方式提交,这里使用GET.get方法来获取key

request.POST.get('key') #如果客户端是POST方式提交,这里使用POST.get方式来获取key

request.path #获取客户端url

request.get_full_path() #获取客户端的URL路径并获取传入的数据

request.method #获取客户端请求的方法

request.FILES #如果客户端上传的是文件需要这个属性,比如<form enctype="multipart/form-data"></form>

request.session #SessionMiddleware中间件,可读写的类似字典对象,表示当前回话
HttpResponse属性

对应HttpResponse对象来说,是由django自动创建,但httpresponse返回是我们自己去定义,每个view请求处理的方法返回必须是一个HttpResponse对象,

template里面的内容并不是html,只是一个模板,因为有渲染功能

HttpResponse类在django.http.response

1
2
3
4
5
6
7
8
9
10
11
12
13
def index(request):
var name = zhuxy
return render(request,'index.html',locals())

#HttpRequest方法
render() #页面渲染,render()和render_to_response()区别是render需要加request而render_to_response()不需要
redirect('url') #页面跳转
HttpResponse('..') #直接放回
HttpResponse(status=200) #直接返回状态,可以是200,404等状态码


#django默认导入render方法,如果需要用到redirect和HttpResponse需要提前导入
from django.shortcuts import render,HttpResponse,redirect
示例
1
2
3
4
5
6
7
8
9
10
11
#写个登录页面如果,账号密码正确则跳到index页面
def login(request):
if request.method == 'POST':
if request.POST.get('user') == 'zhuxuyue' and request.POST.get('passwd') == '1990':
return redirect('index')
else:
return HttpResponse('login false')
if request.method == 'GET':
return render(request,'/login.html')
def index(request):
return HttpResponse('welcome zhuxy')

Django模板

Django 起初定义的html是被直接硬编码在python中,如下代码实例

1
2
3
4
5
from django.shortcuts import render,HttpResponse
import datetime
def showtime(request):
systime = datetime.datetime.now()
return HttpResponse('<h1>system-time:{}</h1>'.format(systime))

这种方式便于解释视图是如何工作的,但是直接将html硬编码到视图不是什么好办法,

页面设计在进行改变都必须对python进行响应修改,站点设计的修改通常比底层python代码修改要多的多,因此如果不在进行python代码修改的情况下设计,那就更加方便。

试想一下,如果一个python开发人员又要设计html,又要写python代码,这样会很繁琐。专人专事,让前端的人搞前端,后端的人搞后端,前段调用后端数据,后端数据返回给前端。

基于这些,我们就可以使用django的模板系统(template system)来实现。

Template语法

模板组成:HTML代码+逻辑控制代码

语法格式:使用双花括号表示变量

template和context对象

template里面都是html模板

context在视图函数中定义的变量

实例

1
2
3
4
5
6
7
#python manage shell
from django.shortcuts import render,HttpResponse
from django.template import Context,Template
t = Template('my name is {{name}}')
c = Context({'name':'zandy'})
t.render(c)
>>>my name is zandy

同一个模板:多个上下文,一旦有了模板对象,就可以通过他渲染多个context,无论何时都可以使用同一个模板渲染多个Context,只进行一次模板创建后多次调用render()方法会渲染会更加高效

1
2
3
4
5
6
7
8
for name in ('zhuxy','yukw','zandy'):
t = Template('hello,{{name}}')
print(t.render(Context({'name':name})))
#如果这样写,模板就创建的三次,没有必要

t = Template('hello:{{name}}');
for name in ('zhuxy','yukw','zandy'):
print(t.render(Context({'name':name})))

Django模板解析快捷,大部分的解析工作都是在后台通过对简短正则表达式一次性调用完成,这个基于xml的模板引擎成鲜明对比

这些引擎承担xml解析器的开销,且往往比Django模板渲染引擎要慢好几个数量级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.shortcuts import render,HttpResponse
from django.template import Context,Template
import time,datetime
# Create your views here.
def showtime(request):
#原始
systime = datetime.datetime.now()
return HttpResponse('<h1>system-time:{}</h1>'.format(systime))

def showtime(request):
#django模板修改视图函数
systime = datetime.datetime.now()
t = Template('<h1>时间:{{ time }}</h1>')
c = Context({'time':systime})
return HttpResponse(t.render(c))

def showtime(request):
#推荐使用该方法
systime = datetime.datetime.now()
return render(request,"index.html",({'time':systime}))
#前段只需要调用这个{{time}}即可使用
Template查询

上面都是只有一层查询,如果是一个列表或者字典或者是一个对象该如何查询?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Animal():
def __init__(self.name,type,sex):
self.name = name
self.type = type
self.se = sex

def query(request):
lst = ['zhuxuyue','yukw','zandy']
return render(request,'index.html',{"action":lst})
//前端模板可以使用action.0,action.1,action2来调用数据,列表的话前端模板使用索引进行调用

dic = {'name':'zhuxuyue','age':18,'gender':'man'}
return render(request,'index.html',{"action":dic})
//前端模板可以使用action.name,action.age,action.gender,通过key取值

aniaml = Animal('拉稀','dog','公') //实例化Animal类对象为aniaml
return render(request,'index.html',locals())
//前端可以使用animal.property来调用
Template调用
1
2
3
4
5
6
7
8
列表调用
<h1>hello,{{action.0}}</h1>

字典调用
<h2>hello,{{action.name}}</h1>

对象调用
<3>hello,{{aniaml.type}}</3>
Template过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
过滤语法格式:
{{obj|filter:param}}

add #调用数据后(必须为数字)增加相应的变量
Context: {'age':18}
Template: {{age|add:10}}
render: 28

capfirst #首字母大写
Context: {'name':'zandy'}
Template: {{name|capfirst}}
render: Zandy

cut #从字符串中移除指定数字
Context: {'name':'HelloWorld'}
Template: {{name|cut:"o"}}
render: HellWrld

date #格式化日期字符串
Context: {'systime':datetime.datetime.now()}
Template: {{systime|date:'Y-m-d'}} 可以设置指定格式

default #如果值是false,就替换成空值
Context: {'test':False}
Template: {{test|default:'空值'}}

default_if_none #如果返回值是None,就替换成默认值,否则用原来的值
Context: {'test':None}
Template: {{test|default:'返回空'}}

addslashes #给变量中的引号加上斜线

length #计算字符串长度

slice #切片

safe #告知游览器,是安全的,如果Context是html语法,这里safe转换成html,否则直接将语法显示出来
Context: {'baidu':'<a href="www.baidu.com">超链接</a>'}
Template: {{baidu|safe}} #如果不加safe会直接将html语法显示出来


除了safe也可以使用mark_safe方式
from django.utils.safestring import mark_safe
txt = mark_safe(<a href="www.baidu.com">百度</a>)
模板直接引入{{txt}},也不会显示语法

除了safe和mark_safe方式,也可以使用autoescape方式
txt = <a href="www.baidu.com">百度</a>
模板使用下面方式
{%autoescape off%}
{{baidu}}
{%endautoescape%}
Template标签
1
使用语法为:{% tag %}表示使用标签
判断
1
2
语法:{% if %} {% endif %}
中间的是逻辑计算,如果是True表示存在,值不能为空并且不是False的布尔值,当然也可以嵌套

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#判断年纪是否为18,如果18返回名称,如果不是18返回不能进入
context:
info = {"name":"zhuxy","age":18}

template:
{% if info.age < 18 %}
<h1>欢迎{{info.name}}</h1>
{% else %}
<h1>未满18,不能进入</h1>
{% endif %}


#也可以嵌套,嵌套必须也要有个{% if %} {% endif %}
{% if %}
{% if %}
{% endif %}
{% endif %}
循环
1
2
语法:{% for %}  {% endfor %}
允许标签按顺序遍历一个序列中的各元素,每次循环模板都会渲染里面的内容

实例

1
2
3
4
5
6
7
8
9
10
#循环一个列表所有元素
context:
classname = ["zhuxuyue","zandy","yukw","zhuxyid"]

template:
{% for user in classname %}
<h1>{{user}}</h1>
{% endfor %}

#在{% for %} {% endfor %} 之间,也可以嵌套{% if %} {% endif %},类似python中一样
计数
1
2
3
4
5
6
7
8
9
10
11
{{ forloop.counter }}		#计数从1开始
{{ forloop.counter0 }} #计数从0开始
{{ forloop.revcounter }} #倒序计数
{{ forloop.recounter0 }} #倒序计数0开始

{{ forloop.first }} #当第一次循环时值为True,在特别情况下有用
{{ if forloop.first }}

#forloop变量和只能在for中得到,当模板解析到达{% endfor %}时{{forloop}}消失
#如果你的模板context已经包含一个叫forloop变量,django会将{% for %}标签替代
#django会在for标签的块中覆盖你定义的forloop变量值,如果其他非循环的地方也可以使用{{forloop}}变量
Template其他标签
1
2
3
{% empty %}

在{% for %}中,如果对象是空的,就显示没有文章
1
2
3
4
5
6
7
{% csrf_token %}

如果设置该选项,那么就不需要在django中设置csrf中间件

通常用于{% csrf_token %}标签,用于防止跨站攻击验证
如果视图里面函数返回是render_to_response方法,则不会生效
说明就是input标签和其他表单标签一起提交给后台,加了一层key和value,提交后value跟随一起提交
1
2
3
{% url 'alias' %}

引用路由的url里面的alias
1
2
3
4
5
6
7
8
{% with %}

用简单的变量代替复杂的变量名称。
{% with hw=helloworld %}
{{ hw }}
{% endwith %}

#用hw变量代替helloworld变量
1
2
3
4
5
6
7
{% verbatime %}

禁止render
{% verbatim %}
{{hello}}
{% endverbatim %}
#render显示的就是{{hello}}这个样子,就算hello在context里面定义了一个变量
1
2
3
{% load %}

加载标签库
自定义filter和simple_tag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
1.在app中创建template模块(必须)
就是在你创建的app下,这里的app是temp,所以在temp下创建templatetags

2.创建任意.py文件,如mytags.py
#more /temp/templatetags/mytags.py
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
#register的名字必须是固定的,不能改变
@register.filter()
def filter_multi(x,y):
return x*y
#自定义filter,这里x默认是调用左边的变量,这里默认有一个不能超过2个

@register.simple_tag
def simple_tag_multi(x,y):
return x*y
#自定义tag

3.使用自定义simple_tag和filter的html文件中导入之前创建的mytag.py
如:{% load mytag %},在template下的html文件中加载定义的方法
{% load_mytag %}

4.使用simple_tag和filter 调用
在template下的html调用定义的filter
{{ name|filter_multi:3 }}
调用自定义filter,就是将name*3,这里的3可以是个对象(列表和字典都可以,但只能穿一个)
{% simple_age_multi 3 10 %}
调用自定义tag,就是将3 跟 10传入到simple_age_multi函数中,不能放在if或者for循环中
{% simple_age_multi age 10 %}

注意:
自定义的tag不能用在if,for控制语句中
自定义的filter不能添加多个参数

5,在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag
INSTALLED_APPS = [
'temp',
]
Template继承

如果一个页面叫index.html,如果想要用其他页面也嵌套index.html就可以使用继承,在index.html(也叫母板),添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{% block test %}
设置母板block名称为test
<h1>release system</h1>
<!--相当于放了一个盒子-->
{% endblock %}

其他页面比如hello.html想调用index.html
{% extends "index.html" %}
调用index.html母板,必须是第一个标记
{{ block.super }}
调用母板上的内容
{% block.test %}
如果想修改,直接调用母板block名称
{% for info in information %}
<h1>{{ info }}</h1>
{% endfor %}
{% endextends %}
1
2
3
4
5
#如果想要修改样式该怎么办?

在母板上样板加个{% block style %} {% endblock %}
其他页面如果想要修改样式,就在{% block style %} {% endblock %}之间修改样式内容。
可以根据需求定义{% block %},就是修改的内容用盒子包装下,下次修改直接调用盒子在修改。

注意事项

1
2
3
4
5
6
7
8
9
10
11
12
如果在母板中使用{% extends %}必须保证其为模板的第一个标记,否则模板不会继承作用

一般来说,基础模板中的{% block %}标记越多越好。子模板不必定义母板中的所有代码,因此你可以用合理的缺省值对一些代码进行填充,然后只对子模板所需的代码块进行(重定义)。这样可扩展性强

如果发现自己在多个模板之间考代码,你应该考虑将代码放到母板的某个{% block %}中,如果你需要访问母板中的模块内容,使用{{block.super}}这个标签,这一个魔法变量将会表现出母模板中的内容,如果只想在上级代码块基础上添加内容,而不是全部重载,改代码块非常有作用

不允许在同一个模板中定义多个同名的{% block %},存在这样限制是因为block标签工作方式是双向的,也就是,block标签不仅挖了一个要填的坑,也定义了在母模板中这个坑所填充的内容,如果模板中出现了两个相同名称的{% block %}标签,母模板将无从得知要使用哪个块的内容

如果想要添加其他页面内容
{% extends "index.html" %}
{% load staticfiles %} #需要引入文件位置
{% include "other.html" %} #引入其他内容
看完了?赏个鸡腿钱,谢谢老板!