模板的功能
模板文件包含两个部分
1.静态内容: CSS JS HTML
2.动态内容: 通过模板语言产生动态页面内容
模板文件的使用
a) 加载模板文件
获取模板文件的内容,产生一个模板对象
template = loader.get_template("xxx.html")
b) 定义模板上下文
给模板文件传递数据 包括request头 和模板变量的值
context = RequestContext(request, {})
c) 模板渲染
用传递的数据替换模板文件中的变量 通过模板对象产生一个标准HTML页面
res_HTML = template.render(context)
d) 返回应答
返回一个HttpResponse的标准HTML页面
renturn HttpResponse(res_HTML)
模板文件的加载顺序
a) 首先去配置文件中指定的模板路径下查找模板文件
b) 去INSTALL_APPS 下面每个应用中有templates包的目录下查找模板文件
c) 再去项目目录下的template 下查找
模板语言
模板语言简称DTL(Django Template Langugae)
模板变量和模板标签的解析顺序
模板变量和模板标签的解析支持两种格式
{{ book.btitle }}
{% if book.id > 3 %}
- 首先把book当成字典 把btitle当成
键名
进行取值book["btitle"] - 把book当成对象 把btitle当成
属性
进行取值 book.btitle - 把book当成对象 把btitle当成对象的
方法
进行取值 book.btitle
{{ book.0 }}
{% if book.0 > 3 %}
- 首先把book当成字典 把0当成
键名
进行取值 book[0] - 把book当成列表 把0当成
下标
进行取值 book[0]
模板变量可以取值 字典(键) 列表(下标) 对象(属性) 对象(方法) 但是都是使用.
来调用
如果模板变量或者模板标签解析失败会产生空字符串填充位置而不会报错
此时可以使用default过滤器
来显示解析为空的位置的信息
模板变量
模板变量不能以下划线开头
{{ 模板变量名 }}
模板标签
{% 模板标签名 %}
常用标签
For循环
{% for 变量 in 列表 %}
{{ forloop.counter }}--{{ 变量 }} # 可以通过counter获得循环的次数
{% empty %} # 当for对象为空时 执行{% empty %} 下的内容
<h1>当空时显示</h1>
{% endfor %} # 模板for循环标签要以{% endfor %} 结束
If分支
{% if 条件1 %}
<h1>满足条件1</h1>
{% elif 条件2 %}
<h1>满足条件2</h1>
{% else %}
<h1>不满足条件<h1>
{% endif %} # 模板if分支标签要以{% endif %} 结束
关系比较标签
>
<
>=
<=
==
!=
{% if book.id > 2 %}
显示的内容
{% endif %}
注意: 进行比较操作时比较标签的两边必须有 空格
逻辑运算
and
or
not
{% if book.bread > 100 or book.bcomment > 100 %}
显示的内容
{% endif %}
其他运算
is
is not
in
not in
标签文档 :
https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#built-in-tag-reference
过滤器
过滤器用于对模板变量
的操作
模板变量|过滤器:参数
注意: 在模板标签
内 |
附近不允许使用空格 但是 在模板变量标签
内 |
附近允许使用空格
所以在使用过滤器时 |
和:
附近建议都不使用空格
内置过滤器
date 改变日期的显示格式
将日期格式过滤为年月日显示
{{ book.bpub_date|date:"Y m j"}}
length 求字符串或列表长度
不再显示title 而是显示title的字符串长度
{{ book.title|length }}
default 设置模板变量的默认值
当模板变量的值为空时 使用默认值填充空
{{ book.xxx|default:"信息为空" }}
过滤器文档 :
https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#built-in-filter-reference
自定义过滤器
自定义的过滤器至少一个参数
最多两个参数
第一个参数是模板变量的返回值
第二个参数是:
后的值
创建自定义过滤器
- 在
应用目录
下创建templatetags
的包 名称必须固定为templatetags
- 在
templatetags
文件夹下python文件中自定义过滤器函数
- 导入
django.template.library
的Library
类 创建一个Library
的对象 - 使用对象的
filter
方法装饰
过滤器函数
在templatetags
下创建一个名为filters.py的文件
from django.template.library import Library
register = Library()
@register.filter
def mod(num, val):
```判断模板变量的值是否被val的值整除```
return num % val == 0 # num由 模板变量传入 val由 |mod: 冒号后的值传入
自定义过滤器的使用
导入包含过滤器的文件
{% load 过滤器的文件 %}
必须在使用自定义过滤器之前被导入
在模板文件中
{% load filters %}
{{ book.id|mod:2 }}
模板注释
单行注释
{# 被注释的内容 #}
多行注释
{% comment %}
被注释的内容
{% endcomment %}
模板注释 与 HTML注释
模板注释
发生在渲染阶段 被注释的不会渲染也就不会在html源码中看到
HTML注释
发生在浏览器渲染阶段 被注释的内容依然可以通过源码查看到
模板继承
当页面中的部分内容相同时使用模板继承来重用模板内容
继承模板内容
在子类模板中使用{% extend "book/base.html" %}
来继承模板
只使用extend
导入的模板内容无法修改
需要在父类模板中设置预留块
来完成子类对父类模板的修改
预留块
1.使用预留块来对被继承模板内容的修改
在父类模板中使用{% block 块名 %}
{% endblock 快名 %}
来定义预留块
{% block b1 %}
<h1>父类预留块内容</h>
{% endblock b1 %}
2.当子模板继承父类模板时同时继承了预留块
在子类模板中使用{% block 块名 %}
{% endblock 快名 %}
来指定要修改的位置
同时可以在块中使用模板变量{{ block.super }} 来调用父类模板中原来的内容
{% extend "book/base.html" %} # 先导入父类模板
{% block b1 %}
{{ block.super }} # 调用原有父类预留块中的内容
<h1>这是子类新内容</h> # 这是子类追加的内容
{% endblock b1 %}
使用{{ block.super }} 可以调用父类预留块中原有的内容
HTML转义
有些html标签是写在数据库中的 当通过render 渲染模板时 html标签默认会被转义
小于号 < 转换为 <
大于号 > 转换为 >
单引号 ' 转换为 '
双引号 " 转换为 "
与符号 & 转换为 &
关闭转义
使用{{模板变量|safe}}
safe模板过滤器关闭转义
如果要多行关闭 使用{% autoescape off %}
{% endautoscape %}
{{book.title|safe}}
{% autoescape off %}
需要关闭转义的内容
{% endautoescape %}
注意:模板硬编码的字符串默认不会经过转义
如果需要转义需要手动转义
{{empty|default:"<h1>默认不转义</h1>"}}
{{empty|default:"<h1>手动转义</h1>"}}
验证登录装饰器
装饰所有需要验证登录后才能访问的视图 让用户只有登录了之后才能访问个别页面
使用装饰器验证用户是否存在某个代表已经登录的session
def login_required(view_func):
def wrapper(request, *args, **kwargs):
if request.session.has_key("islogin"):
return view_func(request, *args, **kwargs)
else:
return redirect("/login")
return warpper
CSRF 防护
CSRF 攻击是当用户在A网站登录后并没有退出本机保存了登录状态的cookie 再访问B网站时 B网站通过ajax在用户不被发现的情况下访问 A网站的并且提交表单 篡改用户在A网站的信息
CSRF只针对POST请求进行验证 不针对GET请求进行验证
当开启防护后 本网站和其他网站提交POST请求时都会提示CSRF防护
在本网站的模板内POST请求中加入{% csrf_token %} 此时只有本网站有{% csrf_token %} 而其他想伪造的网站没有这句代码
防护的原理
当在POST 请求加入{% csrf_token %} 后 页面在渲染后 会在这句代码的位置 加入一个隐藏域
<input type="hidden" name="csrfmiddlewaretoken" value="加密密码..">
注意密码 的内容是当前会话的cookie值+密钥散列值
并且在访问带有POST 请求的页面时 服务器还会 给浏览器一个 键为 csrftoken 的 cookie 值就是隐藏域的value
当用户提交表单时 服务器会检查 隐藏域的value 和 cookie 的value 如果一致 才能成功提交 如果不一致就拒绝访问
如果在伪造的POST中也加入这个隐藏域 那就可以完成 CSRF验证
但是这个隐藏域是A网站给用户的 伪造的网站时无法获取这个隐藏域内容的
并且也无法拿到A网站给浏览器的cookie 因为cookie 是域名安全的不同的域名无法拿到其他域名的cookie
验证码
验证码的目的是为了防止暴力请求
实际上是一个图片
通过模块生成图片
把图片展示出来
保存生成图片时的数据
用于对比输入时的数据 如果 一样 验证成功 如果输入和当初生成图片的数据不同 则失败
URL反向解析
根据URL配置 动态生成模板中的地址
在项目的URL配置文件中设置 include的命名空间
在对应的应用URL配置文件中使用name指定这个url路由的名称
并且需要在应用urls.py的urlpatterns前面加上app_name='[应用名]'
在项目urls.py中
urlpatterns = [
path("", include("book.urls", namespace="temp")),
]
在应用urls.py中
app_name = `[book]`
urlpatterns = [
path("index", view.index, name="app")),
]
在模板中使用
{% url "namespace:name" %} 的方式动态的显示 URL路由中的地址
如果URL 路由带参数
{% url "namespace:name" 参数 %}
如果URL 路由带关键字参数
{% url "namespace:name" 关键字=参数 %}
在视图中使用
导入reverse 函数动态生成对应URL
无参数
reverse("namespace:name")
位置参数
reverse("namespace:name" args=(参数, 参数))
关键字参数
reverse("namespace:name" kwargs={关键字=参数})
实际上模板中的{% url namespace:name %} 就是调用了reverse函数