HTML的静态部分
动态插入内容部分
Django模板语言,简写DTL,定义在django.template包中
由startproject命令生成的settings.py定义关于模板的值:
DIRS定义了一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板源文件
APP_DIRS告诉模板引擎是否应该在每个已安装的应用中查找模板
常用方式:在项目的根目录下创建templates目录,设置DIRS值
DIRS=[os.path.join(BASE_DIR,"templates")]
模板处理
Django处理模板分为两个阶段
Step1 加载:根据给定的标识找到模板然后预处理,通常会将它编译好放在内存中
loader.get_template(template_name),返回一个Template对象
Template对象的render(RequestContext)方法,使用context渲染模板
加载渲染完整代码:
from django.template import loader, RequestContext
from django.http import HttpResponse
def index(request):
tem = loader.get_template('temtest/index.html')
context = RequestContext(request, {})
return HttpResponse(tem.render(context))
快捷函数
from django.shortcuts import render
def index(request):
return render(request, 'temtest/index.html')
模板语言包括
变量
标签 { % 代码块 % }
过滤器
注释{# 代码或html #}
变量
语法:
{{ variable }}
from django.db import models
class HeroInfo(models.Model):
...
def showName(self):
return self.hname
from django.shortcuts import render
from models import *
def index(request):
hero = HeroInfo(hname='abc')
context = {'hero': hero}
return render(request, 'temtest/detail.html', context)
{{hero.showName}}
标签
语法:{ % tag % }
作用
在输出中创建文本
控制循环或逻辑
加载外部信息到模板中供以后的变量使用
for标签
{ %for ... in ...%}
循环逻辑
{{forloop.counter}}表示当前是第几次循环
{ %empty%}
给出的列表为或列表不存在时,执行此处
{ %endfor%}
{ %if ...%}
逻辑1
{ %elif ...%}
逻辑2
{ %else%}
逻辑3
{ %endif%}
{ % comment % }
多行注释
{ % endcomment % }
{ %include "foo/bar.html" % }
{ % url 'name' p1 p2 %}
{ % csrf_token %}
if list1|length > 1
name|lower|upper
list|join:", "
value|default:"什么也没有"
value|date:'Y-m-d'
过滤器参数举例:
显示前30个字:{{ bio | truncatewords:"30" }}
格式化:{{ pub_date | date:"F j, Y" }}
过滤器列表:{{ 123|add:"5" }} 给value加上一个数值
{{ "AB'CD"|addslashes }}: 单引号加上转义号,一般用于输出到javascript中
{{ "abcd"|capfirst }}: 第一个字母大写
{{ "abcd"|center:"50" }}: 输出指定长度的字符串,并把值对中
{{ "123spam456spam789"|cut:"spam" }}: 查找删除指定字符串
{{ value|date:"F j, Y" }}: 格式化日期
{{ value|default:"(N/A)" }}: 值不存在,使用指定值
{{ value|default_if_none:"(N/A)" }}: 值是None,使用指定值
{{ 列表变量|dictsort:"数字" }} :排序从小到大
{{ 列表变量|dictsortreversed:"数字" }} :排序从大到小
{% if 92|divisibleby:"2" %} :判断是否整除指定数字
{{ string|escape }} :转换为html实体
{{ 21984124|filesizeformat }} :以1024为基数,计算最大值,保留1位小数,增加可读性
{{ list|first }} :返回列表第一个元素
{{ "ik23hr&jqwh"|fix_ampersands }}: &转为&
{{ 13.414121241|floatformat }} :保留1位小数,可为负数,几种形式
{{ 13.414121241|floatformat:"2" }}: 保留2位小数
{{ 23456 |get_digit:"1" }} :从个位数开始截取指定位置的1个数字
{{ list|join:", " }} :用指定分隔符连接列表
{{ list|length }} :返回列表个数
{% if 列表|length_is:"3" %} :列表个数是否指定数值
{{ "ABCD"|linebreaks }}: 用新行用 、
标记包裹
{{ "ABCD"|linebreaksbr }}: 用新行用
标记包裹
{{ 变量|linenumbers }}: 为变量中每一行加上行号
{{ "abcd"|ljust:"50" }}: 把字符串在指定宽度中对左,其它用空格填充
{{ "ABCD"|lower }}: 小写
{% for i in "1abc1"|make_list %}ABCDE,{% endfor %}: 把字符串或数字的字符个数作为一个列表
{{ "abcdefghijklmnopqrstuvwxyz"|phone2numeric }}: 把字符转为可以对应的数字??
{{ 列表或数字|pluralize }}: 单词的复数形式,如列表字符串个数大于1,返回s,否则返回空串
{{ 列表或数字|pluralize:"es" }}: 指定es
{{ 列表或数字|pluralize:"y,ies" }}: 指定ies替换为y
{{ object|pprint }}: 显示一个对象的值
{{ 列表|random }}: 返回列表的随机一项
{{ string|removetags:"br p div" }}: 删除字符串中指定html标记
{{ string|rjust:"50" }}: 把字符串在指定宽度中对右,其它用空格填充
{{ 列表|slice:":2" }}: 切片
{{ string|slugify }}: 字符串中留下减号和下划线,其它符号删除,空格用减号替换
{{ 3|stringformat:"02i" }}: 字符串格式,使用Python的字符串格式语法
{{ "EABC D"|striptags }}: 剥去[X]HTML语法标记
{{ 时间变量|time:"P" }}: 日期的时间部分格式
{{ datetime|timesince }}: 给定日期到现在过去了多少时间
{{ datetime|timesince:"other_datetime" }}: 两日期间过去了多少时间
{{ datetime|timeuntil }}: 给定日期到现在过去了多少时间,与上面的区别在于2日期的前后位置。
{{ datetime|timeuntil:"other_datetime" }}: 两日期间过去了多少时间
{{ "abdsadf"|title }}: 首字母大写
{{ "A B C D E F"|truncatewords:"3" }}: 截取指定个数的单词
{{ "111221"|truncatewords_html:"2" }}: 截取指定个数的html标记,并补完整
{{ list|unordered_list }}
: 多重嵌套列表展现为html的无序列表
{{ string|upper }} :全部大写
linkage: url编码
{{ string|urlize }}: 将URLs由纯文本变为可点击的链接。(没有实验成功)
{{ string|urlizetrunc:"30" }}: 同上,多个截取字符数。(同样没有实验成功)
{{ "B C D E F"|wordcount }}: 单词数
{{ "a b c d e f g h i j k"|wordwrap:"5" }}: 每指定数量的字符就插入回车符
{{ boolean|yesno:"Yes,No,Perhaps" }}: 对三种值的返回字符串,对应是 非空,空,None
{#...#}
{# { % if foo % }bar{ % else % } #}
{% comment %}
这是多行注释
{% endcomment %}
示例
查询列表_y单数绿,双数蓝
s
{% for hero in list_y %}
{% if forloop.counter|divisibleby:"2" %}
{{ forloop.counter}}:{{ hero.hname}}
{% else %}
{{ forloop.counter}}:{{ hero.hname}}
{% endif %}
{% empty%}
没有找到!
{% endfor %}
{ %block block_name%}
这里可以定义默认值
如果不定义默认值,则表示空字符串
{ %endblock%}
{ % extends "base.html" %}
{ %block block_name%}
实际填充内容
{ %endblock%}
说明
三层继承结构
{%block title%}{%endblock%} 水果超市
top--{{logo}}
{%block left%}{%endblock%}
{%block content%}{%endblock%}
bottom
2.创建分支模版
{%extends 'temtest/base.html'%}
{%block title%}商品{%endblock%}
{%block left%}
goods left
{%endblock%}
{%extends 'temtest/base.html'%}
{%block title%}用户中心{%endblock%}
{%block left%}
user left
{%endblock%}
{%extends 'temtest/base.html'%}
{%block content%}
首页内容
{%endblock content%}
3.为具体页面创建模板,继承自分支模板
{%extends 'temtest/base_goods.html'%}
{%block content%}
商品正文列表
{%endblock content%}
{%extends 'temtest/base_user.html'%}
{%block content%}
用户密码修改
{%endblock content%}
4.视图调用具体页面,并传递模板中需要的数据
logo='welcome to itcast'
def index(request):
return render(request, 'temtest/index.html', {'logo': logo})
def goodslist(request):
return render(request, 'temtest/goodslist.html', {'logo': logo})
def userpwd(request):
return render(request, 'temtest/userpwd.html', {'logo': logo})
5.配置url
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^list/$', views.goodslist, name='list'),
url(r'^pwd/$', views.userpwd, name='pwd'),
]
视图代码:
def index(request):
return render(request, 'temtest/index2.html',
{
't1': 'hello
'
})
模板代码:
{{t1}}
hello
会被自动转义的字符
< 会转换为<
> 会转换为>
' (单引号) 会转换为'
" (双引号)会转换为 "
& 会转换为 &
{{t1|escape}}
关闭转义
{{ data|safe }}
{ % autoescape off %}
{{ body }}
{ % endautoescape %}
{ { data|default:"123" }}
应写为
{ { data|default:"<b>123</b>" }}
def csrf1(request):
return render(request,'booktest/csrf1.html')
def csrf2(request):
uname=request.POST['uname']
return render(request,'booktest/csrf2.html',{'uname':uname})
url(r'^csrf1/$', views.csrf1),
url(r'^csrf2/$', views.csrf2),
Title
Title
{{ uname }}
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def csrf2(request):
uname=request.POST['uname']
return render(request,'booktest/csrf2.html',{'uname':uname})
运行上面的两个请求,发现都可以请求
保护原理
from django.http import HttpResponse
def verifycode(request):
#引入绘图模块
from PIL import Image, ImageDraw, ImageFont
#引入随机函数模块
import random
#定义变量,用于画面的背景色、宽、高
bgcolor = (random.randrange(20, 100), random.randrange(
20, 100), 255)
width = 100
height = 25
#创建画面对象
im = Image.new('RGB', (width, height), bgcolor)
#创建画笔对象
draw = ImageDraw.Draw(im)
#调用画笔的point()函数绘制噪点
for i in range(0, 100):
xy = (random.randrange(0, width), random.randrange(0, height))
fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
draw.point(xy, fill=fill)
#定义验证码的备选值
str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
#随机选取4个值作为验证码
rand_str = ''
for i in range(0, 4):
rand_str += str1[random.randrange(0, len(str1))]
#构造字体对象
font = ImageFont.truetype('FreeMono.ttf', 23)
#构造字体颜色
fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
#绘制4个字
draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
#释放画笔
del draw
#存入session,用于做进一步验证
request.session['verifycode'] = rand_str
#内存文件操作
from io import BytesIO
buf=BytesIO()
#将图片保存在内存中,文件类型为png
im.save(buf, 'png')
#将内存中的图片数据返回给客户端,MIME类型为图片png
return HttpResponse(buf.getvalue(), 'image/png')
配置url
from . import viewsUtil
urlpatterns = [
url(r'^verifycode/$', viewsUtil.verifycode),
]
显示验证码
看不清,换一个
from django.http import HttpResponse
def verifycodeValid(request):
vc = request.POST['vc']
if vc.upper() == request.session['verifycode']:
return HttpResponse('ok')
else:
return HttpResponse('no')
urlpatterns = [
url(r'^verifycodeValid/$', views.verifycodeValid),
]
第三方
https://blog.csdn.net/chenhua1125/article/details/80113888
https://blog.csdn.net/chenhua1125/article/details/80113703