首页 > 代码库 > Django进阶(二)
Django进阶(二)
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="http://www.mamicode.com/#">跳转</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=http://www.mamicode.com/"提交"> {%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 %}
点击运行,浏览器输入网址,需求实现,并且比之前减少了很多代码。
Django进阶(二)