Django框架 模版(Template)

一.模板系统(Template System)
在下面的例子中,HTML被直接硬编码在Python代码中:

def current_datetime(request):
    now=datetime.datetime.now()
    html="<html><body>Now:%s</body></html>"%now
    return HttpResponse(html)

但这么做有很多缺点:

1.对页面设计进行的任何改变都必须对Python代码进行相应的修改
站点设计的修改往往比底层Python代码的修改要频繁得多
因此如果可以在不进行Python代码修改的情况下变更设计,将会方便得多

2.Python代码编写和HTML设计是两项不同的工作
多数专业的网站开发环境都将二者分配给不同的人员来完成

3.同时进行编写Python代码和制作模板时效率最高

基于这些原因,将页面设计和Python代码分离会使代码更简洁更容易维护;可以使用Django的模板系统来实现这种模式

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

二.模版语法—逻辑控制代码:
1.变量:使用双大括号({{ }})来引用变量

格式:{{var_name}}

(1)模板(Template)对象:

#即render()中的html_name:
from django.template import Template#需要导入
tem_obj=Template(html_name):实例化出模板对象

from django.template import Template
t=Template('<h1>Hello {{name}} </h1>')

(2)上下文(Context)对象:

#即render()中的sub_dict:
from django.template import Context#需要导入
con_obj=Context({"in_html1":sub1,...}):实例化出上下文对象
tem_obj.render(con_obj):进行渲染
#这是render(req,tem_obj,con_obj)的标准写法

>>> python manange.py shell#进入该项目的Django环境
>>> from django.template import Context,Template
>>> from django.shortcuts import render
>>> t=Template('My name is {{ name }}.')
>>> c=Context({'name':'Stephane'})#Context对象
>>> t.render(c)
#结果:'My name is Stephane.'

#一旦有了模板对象,就可以使用该模板源渲染多个context
#只进行1次模板创建然后多次调用render()方法渲染更高效:
#分别创建模板:
for name in ('John', 'Julie', 'Pat'):
    t = Template('Hello, {{ name }}')
    print t.render(Context({'name': name}))
#只创建1此模板:
t=Template('Hello,{{name}}')
for name in ('John', 'Julie', 'Pat'):
    print t.render(Context({'name': name}))
from django.shortcuts import render,HttpResponse
#from django.template.loader import get_template
import datetime
from django.template import Template,Context

#不推荐的写法:
def current_time(req):#原始的视图函数
    now=datetime.datetime.now()
    html="<html><body>时间:<h1>%s</h1></body></html>"%now
    return HttpResponse(html)

def current_time(req):#使用模板的视图函数
    now=datetime.datetime.now()
    t=Template('<html><body>现在时刻是:<h1 style="color:red">{{current_date}}</h1></body></html>')
    #t=get_template('current_datetime.html')
    c=Context({'current_date':now})
    html=t.render(c)
    return HttpResponse(html)
##########################################################
#推荐的写法:
def current_time(req):
    now=datetime.datetime.now()
    return render(req,'current_datetime.html',{'current_date':now})

Django模板解析非常快捷,大部分解析工作都是在后台通过对简短的正则表达式的一次性调用来完成的;这和基于XML的模板引擎截然不同,那些引擎承担了XML解析器的开销,且往往比Django模板渲染引擎慢上几个数量级

(3)深度变量的查找(万能的句点符):

  • 在(2)中通过Context传递的都是str,但Template能处理更复杂的数据结构,如list/dict/obj/自定义对象
  • 在Django模板中遍历复杂数据结构的关键是句点符(.)
#句点可用于访问list的索引:
list.index
  #实例:
	>>> from django.template import Template,Context
	>>> t=Template('Item 2 is {{ items.2 }}.')
	>>> c=Context({'items':['apples','bananas','carrots']})
	>>> t.render(c)
	'Item 2 is carrots.'
##########################################################
#句点可通过dict的key访问其value:
dict.key
  #实例:
	>>> from django.template import Template,Context
	>>> person={'name': 'Sally', 'age': '43'}
	>>> t=Template('{{ person.name }} is {{ person.age }} years old.')
	>>> c=Context({'person':person})
	>>> t.render(c)
	'Sally is 43 years old.'
##########################################################
#也可以通过句点来访问对象的属性:
obj.attr
  #实例:
	>>> from django.template import Template,Context
	>>> import datetime
	>>> d=datetime.date(1993, 5, 2)
	>>> d.year
	1993
	>>> d.month
	5
	>>> d.day
	2
	>>> t=Template('The month is {{date.month}} and the year is {{date.year}}.')
	>>> c=Context({'date':d})
	>>> t.render(c)
	'The month is 5 and the year is 1993.'
##########################################################
#通过实例变量和句点符访问自定义对象的属性:
defined_obj.attr
  #该方法适用于任意的对象
  #实例:
	>>> from django.template import Template,Context
	>>> class Person(object):
	...     def __init__(self,first_name,last_name):
	...         self.first_name,self.last_name=first_name,last_name
	>>> t=Template('Hello,{{person.first_name}} {{person.last_name}}.')
	>>> c=Context({'person':Person('John','Smith')})
	>>> t.render(c)
	'Hello,John Smith.'
##########################################################
#也可以用句点符来引用对象的方法:
obj.func
  #注意:调用方法时没有使用'()',也无法给方法传递参数,只能调用不需要参数的方法
  #实例:
    >>> from django.template import Template,Context
	>>> t=Template('{{var}}--{{var.upper}}--{{var.isdigit}}')
	  #分别调用upper()和isdigit()
	>>> t.render(Context({'var':'hello'}))
	'hello--HELLO--False'
	>>> t.render(Context({'var':'123'}))
	'123--123--True'

(4)过滤器(filter):
参见:https://www.cnblogs.com/Deaseyy/p/10859893.html
过滤器safe参见XSS攻击:
https://blog.csdn.net/weixin_46131409/article/details/106961343

格式:{{obj|filter:param}}
#用在.html中要替换的变量上
#参数说明:
  obj:指定变量
  filter:指定过滤器
  param:过滤器的参数

add:num:给变量加上指定的值
  num:指定加上的值
  #实例:
    value=5#变量在view函数里
    {{value|add:3}}#8
addslashes:在变量中的引号前加上斜线
capfirst:将首字母变为大写
  #实例:
    value='hello'
    {{value|capfirst}}#'Hello'
cut:'char':从字符串中移除指定的字符
  char:指定要移除的字符
  #实例:
    value='he  llo wo r ld'
    {{value|cut:' '}}#'helloworld'
date:'form':格式化日期字符串
  form:指定格式化后的日期格式
  #实例:
    import datetime
    value=datetime.datetime.now()#2020-05-21 22:16:29.435043
    {{value|date:'Y-m-d'}}#2020-5-21
default:val:如果值是False,就替换为默认值;否则不变
  val:指定默认值
  #实例:
    value=[]
    {{value|default:'空的'}}#'空的'
default_if_none:val:如果值是None,就替换为默认值;否则不变
  val:指定默认值
filesizeformat:文件大小(如13KB,4.1MB)
  #实例:
    value='1234'
    {{value|filesizeformat}}
first:取变量的第1个元素
  #实例:
    value='1234'
    {{value|first}}
length:取变量长度
  #实例:
    value='1234'
    {{value|length}}#4
lower:将所有字母变为小写
  #实例:
    value1="aBcDe"
    {{value1|lower}}#'abcde'
safe:像浏览器保证变量合法性,从而进行渲染
  #出于安全考虑,即使后端传入的str的内容为标签
  #浏览器也不进行渲染,直接显示为str
  #使用obj:safe才渲染
  #实例:
    value='<a>跳转</a>'
	{{value}}#'<a>跳转</a>'#是str而非标签
	{{value|safe}}#是标签而非str
	{% autoescape off %}#作用和obj:safe相同
	    {{value}}#是标签而非str
	{% endautoescape %}
slice:'num'|'start:end':进行切片
  num:指定取前几个
  start:开始位置();0为开始;默认为0
  end:结束位置(不含);-1为结尾;默认为-1
  #实例:
    value='1234'
    {{value|slice:":-1"}}
striptags:删除所有HTML标签
  #实例:
    value='<a>跳转</a>'
    {{value|striptags}}
upper:将所有字母变为大写
  #实例:
    value="aBcDe"
    {{value|upper}}#'ABCDE'
urlencode:进行编码
  #实例:
    value='http://www.baidu.com/?a=1&b=3'
    {{value|urlencode}}

(5)函数变量不需要加"()":

{% for item in row.m.all %}
#在Python中是row.m.all()
#m是表中的一对多外键字段,row是表中的1条记录

2.标签(tag)的使用(用{ }和%的组合表示):

格式:{% <tags> %}

(1){% if %}的使用:

  • 相当于Python中的条件判断语句if…elif…else…
{% if 条件 %}:如果条件为True,显示该分支内容
  #即结果为非空且非False的boolean
  #相当于Python中的if
{% elif 条件 %}:类似{% if 条件 %},不过不能用于第1个分支
  #相当于Python中的elif
{% else %}:不满足之上所有条件,显示这部分内容
  #相当于Python中的else
{% endif %}:表示该分支结构结束

#实例:
{% if num >= 100 and 8 %}
    {% 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 %}{% endif %}判断层级
{% if %}接受and/or/not来测试多个变量值或否定1个给定变量
{% if %}不允许同一标签里同时出现andor,否则逻辑容易产生歧义
  #例如下面的标签非法:
    {% if obj1 and obj2 or obj3 %}

(2){% for %}的使用:

{% for i in list %}:按顺序遍历序列中所有元素,每次循环都会渲染{% for %}{% endfor %}间的所有内容
{% endfor %}:表示该循环结束

#实例:
<ul>
	{% for obj in list %}#obj是内容,不是索引
	    <li>{{ obj.name }}</li>
	{% endfor %}
</ul>

#在标签里添加reversed来反序循环列表:
{% for obj in list reversed %}
    ...
{% endfor %}

#{% for %}可以嵌套:
{% for country in countries %}
    <h1>{{ country.name }}</h1>
    <ul>
	    {% for city in country.city_list %}
	        <li>{{ city }}</li>
	    {% endfor %}
    </ul>
{% endfor %}

#注意:
不需要缩进,依靠{% for %}{% endfor %}判断层级
系统不支持中断循环,也不支持continue语句

##########################################################

{% empty %}:如果序列为空,显示{% empty %}的块中的内容

#实例:
{%  for i in li %}
    <li>{{ forloop.counter0 }}----{{ i }}</li>
{% empty %}
    <li>没有相关内容</li>
{% endfor %}
#如果li=[11, 22, 33, 44, 55],结果为:
  #0----11
  #1----22
  #2----33
  #3----44
  #4----55
#如果li=[],结果为:
  #没有相关内容
  • forloop变量:
#内置的forloop变量含有一些属性,可以提供一些关于循环的信息
1.{forloop.counter}:表示循环的次数
  #从1开始计数(第1次循环记为1)
  {% for item in todo_list %}
      <p>{{ forloop.counter }}:{{ item }}</p>
  {% endfor %}
2,{forloop.counter0}:类似于.counter,但从0开始计数
3.{forloop.revcounter}:类似于.counter,但索引是倒过来的
  #内容顺序不变
4.{forloop.revcounter0}:类似于.counter0,但索引是倒过来的
  #内容顺序不变
5.{forloop.first}:判断是否为第1此循环,返回boolean
  {% for object in objects %}   
      {% if forloop.first %}
          <li class="first">#第1次创建class='first'的<li>
      {% else %}
          <li>#之后各次创建普通<li>
      {% endif %}   
              {{ object }}   
          </li>  
  {% endfor %}  

#注意:
1.forloop只能在循环中得到,当模板解析器到达{% endfor %},forloop就消失了
2.如果模板的context已经包含forloop变量
Django会在{% for %}的块中用内置的值覆盖自定义的值
在非循环的地方,自定义的forloop变量仍然可用
总而言之,不要自定义forloop变量就好了!!!

(3){% csrf_token %}的使用:

{% csrf_token %}:加在<form>,用于进行防止跨站攻击的验证
  #注意在view里用的是render_to_response(),不会生效
  #实质是生成1个<input>和其他表单标签一起提交给Server
  #该<input>的内容是1把钥匙(Django开启的Server默认禁止无钥匙的POST请求)
  #钥匙是1组键值对,key就是name属性,value就是value属性
  #加上{% csrf_token %}后,初次请求时,Server会返回包含钥匙的网页,下次就可以提交POST请求了

#要取消这个验证,需要注释掉settings.py中的MIDDLEWARE修改为:
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
  • 实例:
<form action='{$ url 'login' %}' method='post'>
    <p>姓名<input type='text' name='user'></p>
    <p>密码<input type='text' name='pwd'></p>
    <p><input type='submit'></p>
    {% csrf_token %}
</form>

在这里插入图片描述
(4){% url %}的使用:

{% url 'ali' %}:引用路由配置的地址(引用URL的别名)
<!--参数说明:-->
  ali:URL的别名

<form action="{% url "bieming"%}">
          <input type="text">
          <input type="submit" value="提交">
          {%csrf_token%}
</form>

(5){% with %}的使用:

{% with oth=var %}:用更简单的变量名替换复杂的变量名
#如果后端传过来的变量名过长,可以使用该标签进行替换
#参数说明:
  var:要替换的变量名(从后端传入的变量)
  ali:要替换成的变量名(使用时真正使用的别名)
{% endwith %}:表示替换的范围到此结束

{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}

(6){% verbatim %}的使用:

{% verbatim %}:禁止render
{% endverbatim %}:表示禁止render的范围到此结束

#实例:
{% verbatim %}
         {{ hello }}#直接显示{{ hello }},不进行render
{% endverbatim %}

(7){% load %}的使用

{% load py_file %}:加载(自定义)标签库
#参数说明:
  py_file:用来自定义simple_tag和filter.py文件
    #不包括扩展名.py

3.自定义filter和simple_tag:
(1)步骤:

1.在应用文件夹中创建templatetags文件夹(必须)
2.在templatetags中创建任意.py文件并自定义filter/simple_tag

#在templatetags中创建my_tags.py
#my_tags.py中
from django import template
from django.utils.safestring import mark_safe

register=template.Library()#获得1个Library对象
#register这个名字是固定的,不可更改

######################以上3行是固定的######################

@register.filter#自定义filter使用该装饰器
def filter_multi(v1,v2):#自定义1个filter,名字可以随便起
    return  v1*v2
#filter最多传2个参数,其中第1个是该filter作用于的变量

@register.simple_tag#自定义simple_tag使用该装饰器
def simple_tag_multi(v1,v2):#自定义1个simple_tag
    return  v1*v2

@register.simple_tag
def my_input(id,arg):
    result="<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)
3..html文件中导入之前创建的.py文件

#index.html中
{% load my_tags %}#一般放在文件首行
4.调用自定义simple_tag/filter
{{ var|def_filter:para}}:调用自定义filter
  #参数说明:
    var:调用filter的变量
    def_filter:调用的自定义filter
    para:传入的参数;最多1{% def_tag para1 para2 ... %}:调用自定义simple_tag
  #参数说明:
    def_tag:要调用的自定义simple_tag
    para:传入的参数;不同参数用空格分隔

#实例:
#index.html中:传入的num=12
#调用自定义filyer:
{{ num|filter_multi:2 }}#24
{{ num|filter_multi:[22,333,4444] }}
#调用自定义simple_tag
{% simple_tag_multi 2 5 %}#参数不限,但不能放在if/for语句中
{% simple_tag_multi num 5 %}#变量名num不需要再包上{{ }}
5.在settings中的INSTALLED_APPS配置当前app,否则django找不到自定义simple_tag

(2)filter可以用在if等控制语句中,simple_tag不行:

{% if num|filter_multi:30 > 100 %}
    {{ num|filter_multi:30 }}
{% endif %}

4.extend模板继承
见 Web编程.Django框架.模板继承 部分

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值