Template
之前的好多HTML文件中都包含类似“{{ }}”、“{% %}”,其实他们都是模板语言,模板本质上是HTML,但是夹杂了一些变量和标签,可以方便后端的修改前端的内容,而前端代码不用改变。
模板的组成:HTML代码+逻辑控制代码
变量:(使用双大括号来引用变量)语法格式: {{var_name}}
实例一
新建项目:mysit,app名:blog,实现功能:后台获取当前年月日,返回给页面显示
mysit/mysit/urls.py
from django.conf.urls import url, include
# 导入include模块
from django.contrib import admin urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include("blog.urls")) # 所有以blog开头的地址都去bolg app的urls中找对应的视图函数
]
mysit/templates新建myhtml2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ year }}年{{ month }}月{{ day }}日
</body>
</html>
mysit/blog/urls.py
from django.conf.urls import url
from blog import views urlpatterns = [ url(r'index2/$', views.myhtml2),
# 所有blog开头的网址都会找到该py 网址最后是index2则对应views.myhtml2函数 ]
mysit/blog/views.py
from django.shortcuts import render, HttpResponse, redirect import datetime def myhtml2(request):
# 获取当前年月日
year = datetime.datetime.now().year
month = datetime.datetime.now().month
day = datetime.datetime.now().day
# 方法一
# {"year": year, "month": month, "day": day} 键对应myhtml2.html中{{}}内的参数,名称必须一样
# return render(request, "myhtml2.html", {"year": year, "month": month, "day": day})
# 方法二
# locals()代表将该函数内的所有变量传递给myhtml2.html,变量名必须相同
return render(request, "myhtml2.html",locals())
HTML中的“{{ }}”内包含的是变量名称,所需数据由后端提供
获取属性的万能句点.
在到目前为止的例子中,我们传递的简单参数值主要是字符串,然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。
在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。
实例二
mysit/templates/myhtml2.html修改如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ time.year }}年{{ time.month }}月{{ time.day }}日
</body>
</html>
mysit/blog/views.py修改如下:
from django.shortcuts import render, HttpResponse, redirect import datetime def myhtml2(request):
# 方法一
# 获取当前时间对象,有属性.year .month .day 分别获取年月日
# HTML中获取数据 根据 {{ time.year }}年{{ time.month }}月{{ time.day}}日
# time = datetime.datetime.now() # 方法二
# 获取当前时间对象,分别获取年月日添加到列表中
# HTML中获取数据 根据 {{ time.0 }}年{{ time.1 }}月{{ time.2}}日
# time = [ datetime.datetime.now().year, datetime.datetime.now().month,
# datetime.datetime.now().day] # 方法三
# 获取当前时间对象,分别获取年月日添加到字典中
# HTML中获取数据 根据 {{ time.year }}年{{ time.month }}月{{ time.day}}日
time = {"year": datetime.datetime.now().year, "month": datetime.datetime.now().month,
"day": datetime.datetime.now().day} return render(request, "myhtml2.html", locals())
所以在模板语言中句点(.)可以获取任意对象的任意属性
变量过滤器
# 语法格式: {{obj|filter:param}} # value1 = "aBcDe"
# HTML代码: value1|upper
# 执行结果: ABCDE # value3 = 'he llo wo r ld'
# HTML代码: value3|cut:'he'
# 执行结果: llo wo r ld # date 格式化日期字符串
# value4 = datetime.datetime.now()
# HTML代码: value4|date:'Y-m-d'
# 执行结果: 2016-11-29 # value5 = []
# HTML代码: value5|default:'空的'
# 执行结果: 空的 # value6 = '<a href="#">跳转</a>'
# HTML代码: value6|safe
# 执行结果: 跳转 # HTML代码: value6|striptags
# 执行结果: 跳转 # value7 = '1234'
# HTML代码: value7 | filesizeformat
# 执行结果: 1.2 KB # HTML代码: value7 | first
# 执行结果: 1 # HTML代码: value7 | length
# 执行结果: 4 # HTML代码: value7 | slice: ":-1"
# 执行结果: 123 # value8 = 'http://www.baidu.com/?a=1&b=3'
# HTML代码: value8|urlencode
# 执行结果: http%3A//www.baidu.com/%3Fa%3D1%26b%3D3
模板标签 标签(tag)的使用(使用大括号和百分比的组合来表示使用tag) {% tag %}
------------------------{%url "name" %}:引用路由配置的地址
<form action="{% url "aaa"%}" > #代表该表单提交的数据会交给 urls.py中 别名为 “aaa” 所对应的视图函数去执行
<input type="text">
<input type="submit"value="提交">
{%csrf_token%}
</form>
------------------------{%csrf_token%}:用于生成csrf_token的标签,用于防治跨站攻击验证。注意如果你在视图函数中用的是render_to_response返回页面的方法,则该标签不会生效
其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。
实例三
在实例一的基础上
mysit/templates/myhtml2.html修改如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action={% url "aaa" %} method="post"> # 在urls.py中找到别名为“aaa”所对应的函数提交数据
<input type="submit">
</form> </body>
</html>
mysit/blog/urls.py
from django.conf.urls import url
from blog import views urlpatterns = [ url(r'index2/$', views.myhtml2, name="aaa"),
# 所有blog开头的网址都会找到该py 网址最后是index2 则对应views.myhtml2函数,提交表单,因为其别名为aaa,所以提交表单时执行views.myhtml2函数 ]
运行,点击提交按钮你会发现以下错误
Forbidden (403) CSRF verification failed. Request aborted.
Help Reason given for failure: CSRF token missing or incorrect. In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure: Your browser is accepting cookies.
The view function passes a request to the template's render method.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login. You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed. You can customize this page using the CSRF_FAILURE_VIEW setting.
原因是django为了在用户提交表单时防止跨站攻击所做的保护
只需在HTML文件的表单中添加{%csrf_token%} 便可以解决问题
------------------------if判断{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容
{% if num >= 100 %} {% if num > 200 %}
<p>num大于200</p>
{% else %}
<p>num介于100和200之间</p>
{% endif %} {% elif num < 100 %}
<p>num小于100</p> {% else %}
<p>num等于100</p> {% endif %} {% if %} 标签接受and,or或者not来测试多个变量值或者否定一个给定的变量
{% if %} 标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的: {% if obj1 and obj2 or obj3 %}
------------------------for循环{% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
{% for obj in list %} #代表开始执行该次循环
<li>{{ obj}}</li>
{% endfor %} #代表结束该次循环 #在标签里添加reversed来反序循环列表: {% for obj in list reversed %}
...
{% endfor %} #{% for %}标签可以嵌套: {% for i in list1 %} {% for ii in list2 %}
{{ ii }}
{% endfor %}
{% endfor %} #系统不支持中断循环,系统也不支持continue语句,{% for %}标签内置了一个forloop模板变量,
#这个变量含有一些属性可以提供给你一些关于循环的信息 1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1: {% for item in todo_list %}
{{ forloop.counter }}: {{ item }}
{% endfor %}
2,forloop.counter0 类似于forloop.counter,但它是从0开始计数,第一次循环设为0
3,forloop.revcounter
4,forloop.revcounter0
5,forloop.first当第一次循环时值为True,在特别情况下很有用: {% for object in objects %}
{% if forloop.first %}
<li class="first">
{% else %}
<li>{% endif %}
{{ object }}
</li>
{% endfor %} # 富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了
# 如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它
# Django会在for标签的块中覆盖你定义的forloop变量的值
# 在其他非循环的地方,你的forloop变量仍然可用 #{% empty %} {{li }}
{% for i in li %}
<li>{{ forloop.counter0 }}----{{ i }}</li>
{% empty %}#如果 li是空的可迭代对象 则执行该行代码下的内容 否不执行
<li>this is empty!</li>
{% endfor %}
到目前为止,我们的模板范例都只是些零星的 HTML 片段,但在实际应用中,你将用 Django 模板系统来创建整个 HTML 页面。 这就带来一个常见的 Web 开发问题: 在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?
解决该问题的传统做法是使用 服务器端的 includes ,你可以在 HTML 页面中使用该指令将一个网页嵌入到另一个中。 事实上, Django 通过刚才讲述的 {% include %} 支持了这种方法。 但是用 Django 解决此类问题的首选方法是使用更加优雅的策略—— 模板继承 。
本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。
------------------------{%block block_name %} {% endblock %}
------------------------{% extends "HTML_NAME.html" %}
实例四
实现下面功能:
分别新建base.html menu1.html menu2.html。menu1.html menu2.html与base.html一样,只需修改content盒子内的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.head{
height: 50px;
background-color: blue;
}
.menu{
float: left;
background-color: aqua;
height: 570px;
width: 20%;
}
.content{
float: left;
height: 570px;
width: 80%;
background-color: blueviolet;
}
.footer{
height: 53px;
background-color: blue;
clear: both;
} </style> </head>
<body style="margin: 0">
<div>
<div class = "head"></div>
<div>
<div class = "menu">
{# 根据url分发系统中的别名进行跳转#}
<a href="{% url "menu1" %}">菜单一</a><br>
<a href="{% url "menu2" %}">菜单二</a> </div> <div class = "content">{#menu1.html menu2.html 在此添加不同的内容#}</div> </div>
<div class = "footer"></div>
</div>
</body>
</html>
views.py代码如下
from django.shortcuts import render, HttpResponse, redirect def base(request):
return render(request, "base.html") def menu1(request):
return render(request, "menu1.html") def menu2(request):
return render(request, "menu2.html")
urls.py代码如下
from django.conf.urls import url
from blog import views urlpatterns = [
url(r'^blog/base/$', views.base,name="base"),
url(r'^blog/base/menu1/$', views.menu1,name="menu1"),
url(r'^blog/base/menu2/$', views.menu2, name="menu2"),
]
点击运行,浏览器输入网址,就会得到想要的效果,你也发现了base.html menu1.html menu2.html三个HTML文件有很多的重复代码,那么就让我们用{%block block_name %} {% endblock %}和{% extends "HTML_NAME.html" %} 来省略重复代码
base.html 修改如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.head{
height: 50px;
background-color: blue;
}
.menu{
float: left;
background-color: aqua;
height: 570px;
width: 20%;
}
.content{
float: left;
height: 570px;
width: 80%;
background-color: blueviolet;
}
.footer{
height: 53px;
background-color: blue;
clear: both;
} </style> </head>
<body style="margin: 0">
<div>
<div class = "head"></div>
<div>
<div class = "menu">
{# 根据url分发系统中的别名进行跳转#}
<a href="{% url "menu1" %}">菜单一</a><br>
<a href="{% url "menu2" %}">菜单二</a> </div> {#将之前的代码(<div class = "content"> </div>)替换为下面的代码#}
{% block base %} {% endblock %}
{#base 是这个block的名字,之后的子HTML继承的时候也会标注这个名字,用来进行替换。 {% block base %}被替换的内容{% endblock %} #} </div>
<div class = "footer"></div>
</div>
</body>
</html>
menu1.html menu2.html修改如下
{% extends "base.html" %}
{#上面这行代码代表继承自base.html#} {#下面这个block代码块里的内容将会代替父HTML(base.html) 里面 名为base的block代码块#} {% block base %} <div class = "content">菜单一</div> {% endblock %}
点击运行,浏览器输入网址,需求实现,并且比之前减少了很多代码。