Django之模板层

时间:2019-11-12
本文章向大家介绍Django之模板层,主要包括Django之模板层使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
django模板

第一:模板介绍

当浏览器发送请求,urls会把请求信息转发给视图函数(views)进行处理,
而视图函数在经过一系列处理后必须要返回信息给浏览器,如果我们要返回html标签,
css等数据给浏览器渲染,可以在view.py中写html。
上面的一种方式可以让我们清楚的看到前端界面,但是这种前端代码与后端耦合到了一起,会存在一下问题

1.程序的可维护性和可扩展性问题    
前端界面一旦需要重新设计,修改,则必须对后端的python代码进行相应的修改,然而前端界面的修改往往比后端python代码
要繁琐的多,因此如果可以在不进行修改python代码的情况下变更前端界面的设计,那会方便很多
2.开发效率问题
python代码和html是两项不同的工作,大多数专业的网站都回分配给不同的员工或者不同部门来完成,两者同时进行可以提高开发效率

基于以上的原因,django专门提供了一个模板系统来实现这种模式

django模板=HTML代码+模板语法
存放与templates目录下的html文件称之为模板文件,如果我们想要返回的html页面中的数据是动态的,那么必须在html页面中嵌入变量,
这就用到了django的模板语法,django模板语法有一下重点:

1.变量: {{ 变量名 }}
  1.1 深度查询:句点符的应用
  1.2 过滤器
2.标签: {{% 标签名 %}}
3.自定义标签和过滤器
4.模板的导入和继承

第二:模板的语法---变量

2.1 变量的基本用法

变量看起来就像这样: {{ variable }}

当模版引擎遇到一个变量,它将从上下问context中获取这个变量的值,然后用该值替换掉它本身。

2.1.1 : 变量的命名包括任何字母数字以及下划线(“_”)的组合。

2.1.2 : 点(.)在变量中出现有特殊的含义,如2.2深度查询

2.1.3 : 变量名称中不能有空格或者标点符号

具体用法:views.py

from django.shortcuts import render,HttpResponse
from django.shortcuts import reverse
from django.shortcuts import redirect
import datetime
# Create your views here.
from django.views import View

def ylqh(request):
    #传给模板的变量可以是python的任何类型
    msg="zzl ylqh cyy 'aaaa' sss number"
    dic={'k1':2,'k2':3}
    lis=[
        {'name':'zzl'},
        {'name':'cyy'},
        {'name':'ylqh'},
        {'name':'zcc'},
        {'name':'zyc'},
         ]
    class Person(object):
        def __init__(self,name,age):
            self.name=name
            self.age=age
    obj=Person('zzl',18)
    date=datetime.datetime.now()
    tag = [date,1024,'sgDDDs',obj]
    url = '<script>alert(123)</script>'
    url2 = '<a href="https://www.baidu.com">url</a>'
    # return render(request,'ylqh.html',{'msg':msg,'dic':dic,'obj':obj,'tag':tag})
   #1.render函数的第三个参数包括了要传给模版的变量值,是一个字典类型,该字典类型中的key必须与模版文件中的变量名称相对应,render函数回去templates目录下找到模板问及那,然后根据字典中的key对应到模板文件中的变量名进行赋值操作,最后将赋值后的模版文件内容返回给浏览器
   #2.可以将render函数的第三个参数简写为locals(),如下:        
    return render(request,'ylqh.html',locals())
    #locals()会将函数test内定义的名字与值转换为字典中的k与v

ylqh.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
</head>
<body>
<p>{{ msg }}</p>
<p>{{ dic }}</p>
<p>{{ obj }}</p>
<p>{{ lis }}</p>
</body>
</html>

 2.2 深度查询--->句点号的使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
</head>
<body>

调用 字符串对象的upper方法
<p>{{ msg.upper }}</p>

取字典中k1对应的值
<p>{{ dic.k1 }}</p>

取对象的name属性
<p>{{ obj.name }}</p>

取列表的第一个元素的name属性
<p>{{ lis.1.name }}</p>
</body>
</html>

2.3 过滤器的使用

过滤器类似于python的内置函数,用来把视图传入的变量值加以修饰后,在显示,并且一个过滤器的输出可以应用与下一个过滤器,如下:

{{ 变量名|过滤器名:传给过滤器的参数 }}
{{ 变量名|过滤器名:传给过滤器的参数 | 过滤器名:过滤器参数 |...}}

内置过滤器用法:

1.default:如果一个变量的值为False或者为空,使用default后指定的默认值,否则,使用变量本身的值,如果value='' ,则输出“nothing”
{{ value|default:"nothing" }}

2. default_if_none: 如果(且仅当)value为None,则使用给定的默认值
{{ value|default_if_none:"nothing" }}
如果value是None,则输出为nothing,如果value是其他值,例如'python',则会输出python

3. length:返回值的长度。它对字符串和列表,字典都起作用。
{{ tag | length }}
如果tag是['a', 'b', 'c', 'd'],那么输出4。

4. length_is:检查列表,字符串是否是指定的长度的值
{{ tag | length_is:'4' }}

5. filesizeformat:格式化为“人类可读”文件大小单位(即'13 KB'4.1 MB''102 bytes'等)。
{{ value|filesizeformat }}
如果value是1024,输出将会是1.0KB 

6. add: 把add后的参数加给value
{{ value | add:" python" }}
如果value是hello,则会输出“hello python”
{{ value|add:"3" }}
如果value是5,则会输出8
过滤器首先会强制把两个值转换成Int类型,如果强制转换失败,会用各种方式把两个值相加
{{ first|add:second }}
如果first是[1, 2, 3],second是[4, 5, 6], 将会输出[1, 2, 3, 4, 5, 6]

7. addslashes
在引号前面加上斜杆。常用于在CSV中转义字符串。像这样:
<p>{{ value | addslashes }}</p>
如果value是"I'm using Django", 输出将变成 "I\'m using Django".

8.capfirst
{{ msg | capfirst }}
如果msg是django,输出则会变成“Django”

9.center
在给定的宽度范围内居中.
"{{ value|center:"15" }}"
如果value是"Django",输出将是Django。

10. cut
移除value中所有的与给定参数相同的字符串
{{ msg | cut:"sss" }}
如果msg为"zzl ylqh cyy 'aaaa' sss number",输出结果将是"zzl ylqh cyy 'aaaa' number"

11. date
根据给定格式对一个日期变量进行格式化
{{ value|date:"Y-m-d" }}
如果日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-11-10

12. dictsort 接受一个包含字典元素的列表,并返回按参数中给出的键排序后的列表
{{ value|dictsort:"name" }}
如果value为:
[
    {'name': 'zed', 'age': 19},
    {'name': 'amy', 'age': 22},
    {'name': 'joe', 'age': 31},
]
则输出为:
[
    {'name': 'amy', 'age': 22},
    {'name': 'joe', 'age': 31},
    {'name': 'zed', 'age': 19},
]
还可以用作这样的排序:
{% for book in books|dictsort:"author.age" %}
    * {{ book.title }} ({{ book.author.name }})
{% endfor %}
如果books是:
[
    {'title': '1984', 'author': {'name': 'George', 'age': 45}},
    {'title': 'Timequake', 'author': {'name': 'Kurt', 'age': 75}},
    {'title': 'Alice', 'author': {'name': 'Lewis', 'age': 33}},
]
则输出为:
* Alice (Lewis)
* 1984 (George)
* Timequake (Kurt)
dictsort也可以按指定索引对多维列表进行排序,如下:
{{ value|dictsort:0 }}
如果value是:
[
    ('a', '42'),
    ('c', 'string'),
    ('b', 'foo'),
]
那么输出的将是:
[
    ('a', '42'),
    ('b', 'foo'),
    ('c', 'string'),
]
注意:这里必须提供的是整数的索引,不能是字符串的,如下会产生空的输出:
{{ values|dictsort:"0" }}

13.dictsortreversed
同12的用法相同,作用相反,具有反序排列的功能

14.divisibleby
如果value可以被参数整除,则返回True
{{ value | divisibleby:2 }}
{{ 222 | divisibleby:2 }}  则返回True
{{ 222 | divisibleby:9 }}  则返回False

15. escape
转义字符串的HTML。

转义仅在字符串输出时应用,因此在链接的过滤器序列中escape的位置无关紧要,就像它是最后一个过滤器。 如果要立即应用转义,请使用force_escape过滤器。

16.force_escape
立即转义HTML字符串。

17. escapejs
转义用于JavaScript字符串的字符。 确保在使用模板生成JavaScript / JSON时避免语法错误。
{{ value|escapejs }}
如果value为testing\r\njavascript \'string" <b>escaping</b>,输出将为testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E。

18.first
返回列表中的第一项
{{ value|first }}
如果value是列表['zzl''cyy''ylqh'] ,输出将为'zzl'19. last
返回列表中的最后一个项目。类似first过滤器
{{ value|last }}
如果value是列表['zzl''cyy''ylqh'] ,输出将为'ylqh'20. floatformat
当不使用参数时,将浮点数舍入到小数点后一位,但前提是要显示小数部分。 如下:
value           模板语法                输出
34.23234    {{ value | floatformat }}   34.2
34.00000    {{ value | floatformat }}   34
34.26000    {{ value | floatformat }}   34.3

如果与数字整数参数一起使用,将数字四舍五入为小数位数。 像这样:
value           模板语法                输出
34.23234    {{ value | floatformat:3 }} 34.232
34.00000    {{ value | floatformat:3 }} 34.000
34.26000    {{ value | floatformat:3 }} 34.260

特别有用的是传递0(零)作为参数,它将使float浮动到最接近的整数。
value           模板语法                输出
34.23234    {{ value | floatformat:“0” }}   34
34.00000    {{ value | floatformat:“0” }}   34
39.56000    {{ value | floatformat:“0” }}   40

如果传递给floatformat的参数为负,则会将一个数字四舍五入到小数点后(负几)的位置,但前提是要显示一个小数部分。 如下:
value           模板语法                输出
34.23234    {{ value | floatformat:“ - 3” }}    34.232
34.00000    {{ value | floatformat:“ - 3” }}    34
34.26000    {{ value | floatformat:“ - 3” }}    34.260

21.get_digit
给定一个整数,返回所请求的数字,1表示最右边的数字,2表示第二个最右边的数字,以此类推。
{{ value|get_digit:"8" }}
如果value为0123456789,则输出2。

22. iriencode
将IRI(国际化资源标识符)转换为适合包含在URL中的字符串。
{{ value|iriencode }}
如果value是?test=1&me=2,输出则是?test=1&amp;me=2

23. join
使用字符串连接列表,类似Python的str.join(list)
{{ lis | join:'--' }}
如果lis是列表 
   lis=[
        {'name':'zzl'},
        {'name':'cyy'},
        {'name':'ylqh'},
        {'name':'zcc'},
        {'name':'zyc'},
         ] 
输出为:
{'name': 'zzl'}--{'name': 'cyy'}--{'name': 'ylqh'}--{'name': 'zcc'}--{'name': 'zyc'}

24.linebreaks
替换纯文本中的换行符为<p>标签
{{ value|linebreaks }}
如果value是Joel\nis a slug,输出将为<p>Joel<br />is a slug</p>25.linebreaksbr
替换纯文本中的换行符为<br />标签。
{{ value|linebreaksbr }}
如果value是Joel\nis a slug,输出将为Joel<br />is a slug。

26. linenumbers
显示带行号的文本
{{ value|linenumbers }}
如果value为:
zzl
cyy
则输出:
1. zzl
2. cyy

27.ljust:给定宽度下左对齐。
"{{ value|ljust:"10" }}"
如果value为Django,则输出为Django。

28.rjust :右对齐给定宽度字段中的值
"{{ value|rjust:"10" }}"

29.upper
将字符串转换为大写
{{ value | upper }}
如果value为zzl ,则输出为ZZL

30 lower
将字符串转化为小写
{{ value | lower }}
如果value为ZZl 则输出为zzl

31. make_list
将对象转换为字符的列表。对于字符串,直接拆分为单个字符的列表。对于整数,在创建列表之前将参数强制转换为unicode字符串。
{{ value|make_list }}
如果value是字符串"zzl",输出是列表['z','l','l']
如果value是345,输出的列表['3','4','5']

32.phone2numeric
将电话号码(有可能含有字母)转化为等效数字
{{ value|phone2numeric }}
如果value为800-COLLECT,输出将为800-2655328

33. pluralize
如果值不是1,则返回一个复数形式,通常在后面添加's'表示。
例如:
You have {{ num_messages }} message{{ num_messages|pluralize }}.
如果num_messages是1,则输出为You have 1 message。 如果num_messages是2,输出为You have 2 messages。
另外如果需要的不是's'后缀的话, 可以提供一个备选的参数给过滤器:
You have {{ num_walruses }} walrus{{ num_walruses|pluralize:"es" }}.
对于非一般形式的复数,可以同时指定单复数形式,用逗号隔开。例如:
You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}.

34.pprint:用于调试的过滤器

35.random 返回给定列表或者字符串中的随机数
{{ value|random }}
如果value为zzl ,则会随机返回z或者l,如果value为['zzl','cyy','ylqh'],则随机返回zzl或者cyy或者ylqh

36.safe:将字符串标记为安全,不需要转义
为了安全考虑,Django的模板会对html标签,JS等语法的标签进行自动转义
例如:value="<script>(123)</script>",模板变量 {{ value }}会被渲染城&lt;script&gt;alert(123)&lt;/script&gt; 交给浏览器后会被解析成普通字符"<script>alert(123)</script>",失去了js代码的语法意义,但是如果我们想让模板变量{{ value }}被渲染的结果又有语法意义,那么就用到了safe,比如 value='<a href="https://www.baidu.com">url</a>',加上safe,则会变成真正的超链接,不加的话,就是普通的字符串。
{{ value | safe }}

37.safeseq
将safe过滤器应用于序列的每个元素。 与对序列进行其他过滤操作(例如join)一起使用时非常有用。
{{ value|safeseq|join:", " }}
在这种情况下,不能直接使用safe过滤器,因为它首先将变量转换为字符串,而不是使用序列的各个元素。

38. slice 返回列表的一部分。也就是切片,与Python的列表切片相同的语法。
{{ value|slice:":2" }}
如果value是['a''b''c'] ,输出将为['a''b']。

39.slugify
转换为ASCII。空格转换为连字符。删除不是字母数字,下划线或连字符的字符。转换为小写。还会去除前导和尾随空格。
{{ value|slugify }}
如果value是Yle is a slug,输出为yle-is-a-slug。

40.strringformat 根据参数,格式化变量。
{{ value|stringformat:"E" }}
如果value为10,则输出为:1.000000E+01

41.striptags
尽可能的去除HTML中的标签
{{ value|striptags }}
如果value是<b>zzl</b> <button>is</button> a <span>man</span>,输出zzl is a man42.time
根据给定的格式,格式化时间。给定格式可以是预定义的TIME_FORMAT,也可以是与date过滤器相同的自定义格式。
{{ value|time:"H:i" }}
如果value等于datetime.datetime.now(),则输出字符串00:08
time过滤器只接受格式字符串中与时间相关的参数,而不是日期。如果需要格式化date值,请改用date过滤器

43.timesince
将日期格式设为自该日期起的时间(例如,“4天,6小时”)
采用一个可选参数,它是一个包含用作比较点的日期的变量。例如,如果blog_date是表示2006年6月1日午夜的日期实例,并且comment_date是2006年6月1日08:00,则以下将返回“8 hours”:
{{ blog_date|timesince:comment_date }}

44.timeuntil
类似于timesince,它测量从现在开始直到给定日期或日期时间的时间。例如,如果今天是2006年6月1日,而conference_date是2006年6月29日,则{{ conference_date | timeuntil }}将返回“4 weeks”

可选参数是一个包含用作比较点的日期变量。如果from_date为2006年6月22日,则以下内容将返回“1 weeks”
{{ conference_date|timeuntil:from_date }}

45.title 将所有单词的首字母大写,其它字母小写
{{ value|title }}
如果value为“my FIRST post”,输出将为“My First Post”

46.truncatechars
如果字符串包含的字符总个数多于指定的字符数量,那么会被截断掉后面的部分。截断的字符串将以“...”结尾
{{ value|truncatechars:9 }}
如果value是Joel is a slug,输出为Joel i...

47.truncatechars_html
类似于truncatechars,但是会保留HTML标记
{{ value|truncatechars_html:9 }}
如果value是<p>Joel is a slug</p>,输出<p>Joel i...</p>

48.truncatewords
在一定数量的字数后截断字符串。与truncatechars不同的是,这个以字的个数计数,而不是字符计数
{{ value|truncatewords:2 }}
如果value 是Joel is a slug, 输出为Joel is ...
字符串中的换行符将被删除

49.truncatewords_html
类似于truncatewords,但是保留HTML标记
{{ value|truncatewords_html:2 }}
HTML内容中的换行符将保留

50.unordered_list:接收一个嵌套的列表,返回一个HTML的无序列表,但不包含开始和结束的<ul>标签
例如,如果var 包含['States', ['Kansas', ['Lawrence', 'Topeka'], 'Illinois']], 那么{{ var|unordered_list }}将返回
<li>States
<ul>
        <li>Kansas
        <ul>
                <li>Lawrence</li>
                <li>Topeka</li>
        </ul>
        </li>
        <li>Illinois</li>
</ul>
</li>

51.urlencode:转义要在URL中使用的值。
{{ value|urlencode }}
如果value为https://www.example.org/foo?a=b&c=d,输出https%3A//www.example.org/foo%3Fa%3Db%26c%3Dd

52.urlize:将文字中的网址和电子邮件地址转换为可点击的链接。
该模板标签适用于前缀为http://,https://的链接,或者www
由urlize生成的链接会向其中添加rel="nofollow"属性
{{ value|urlize }}
如果value是Check out www.djangoproject.com,输出Check out <a href="http://www.djangoproject.com" rel="nofollow">www.djangoproject.com</a>

除了超级链接之外,urlize也会将电子邮件地址转换为邮件地址链接。 如果value是Send questions to foo@example.com,输出将是Send questions to <a href="mailto:foo@example.com">foo@example.com</a>

53.urlizetrunc:将网址和电子邮件地址转换为可点击的链接,就像urlize,但截断长度超过给定字符数限制的网址
{{ value|urlizetrunc:15 }}
如果value是Check out www.djangoproject.com,将输出Check out <a href="http://www.djangoproject.com" rel="nofollow">www.djangopr...</a>'
(注:此过滤器只用于纯文本)

54.wordcount:返回单词的个数
{{ value|wordcount }}
如果value是Zzl cyy ylqh,输出3

55.wordwrap:以指定的行长度,换行单词
{{ value|wordwrap:5 }}

56.yesno
将True,False和None,映射成字符串‘yes’,‘no’,‘maybe’
{{ value|yesno:"yeah,no,maybe" }}

第三:模板的语法---标签

标签是为了在模板中完成一些特殊功能,语法为{% tag % },一些标签还需要搭配结束标签{ % endtag % } 

详解两个例子

eg1:for标签

循环序号可以通过{{ forloop }}显示
forloop.counter         当前循环的索引值(从1开始)
forloop.counter0        当前循环的索引值(从0开始)
forloop.revcounter      当前循环的倒叙索引值(从1开始)
forloop.revcounter0     当前循环的倒叙索引值(从0开始)
forloop.first           当前循环是第一次循环则返回True,否则返回False 
forloop.last            当前循环是最后一次循环则返回True,否则返回False
forloop.parentloop      本层循环的外层循环

urls.py

from django.urls import include,path,re_path,register_converter
from app01 import views

urlpatterns = [
    re_path(r'ylqh',views.ylqh),
]

views.py

zzl@jenkins:~/workspace/mysite/app01$ 
zzl@jenkins:~/workspace/mysite/app01$ ls
admin.py  apps.py  __init__.py  migrations  models.py  __pycache__  tests.py  urls.py  views.py
zzl@jenkins:~/workspace/mysite/app01$ cat views.py 
from django.shortcuts import render,HttpResponse
from django.shortcuts import reverse
from django.shortcuts import redirect
import datetime
# Create your views here.
from django.views import View
# {'name': 'zzl'}--{'name': 'cyy'}--{'name': 'ylqh'}--{'name': 'zcc'}--{'name': 'zyc'}
def ylqh(request):
    names=['zzl','cyy','ylqh']
    dic = {'name':'zzl','age':'18','sex':'male'}
    lis = []
    return render(request,'ylqh.html',locals())

ylqh.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
</head>
<body>
<hr>
{% for name in names %}
    <p> {{ forloop.counter0 }} {{ name }} </p>
{% endfor %}
输出:
0 zzl
1 cyy
2 ylqh

<hr>
{% for name in names reversed %}
    <p> {{ forloop.counter0 }} {{ name }} </p>
{% endfor %}
输出:
0 ylqh
1 cyy
2 zzl

<hr>
{% for k,v in dic.items %}
    <p> {{ forloop.counter0 }} {{ k }} {{ v }} </p>
{% endfor %}
输出:
0 name zzl
1 sex male
2 age 18

<hr>
{% for item in lis %}
    <p> {{ item }} </p>
    {% empty %}
    <p>sorry,no value here</p>
{% endfor %}
输出:
sorry,no value here
</body>
</html>

eg2:if标签

1.{% if 条件 %}条件为真时if的字句才会生效,条件也可以是一个变量,if会对变量进行求值,在变量值为空,或者视图没有为其传值的时候均为False
2、语法:
{%  if num > 100 or num < 0 %}
            <p>无效</p>
{% elif num > 80 and num < 100 %}
            <p>优秀</p>
{% else %}
            <p>差不多</p>
{% endif %}

3.if 语句还支持 and 、or、==、>、<、!=、<=、>=、in、not、in、is、is not进行判断

urls.py

from django.contrib import admin
from django.urls import include,path,re_path,register_converter
from app01 import views

urlpatterns = [
    re_path(r'^$',views.index),
    re_path(r'^index/$',views.index),
    re_path(r'^login/$',views.login),
]

views.py

def index(request):
    return render(request,'index.html')

def login(request):
    if request.method == 'GET':
        return render(request,'login.html')

    name=request.POST.get('name')
    pwd=request.POST.get('pwd')
    if name == 'zzl' and pwd == '123':
        current_user=name
        return render(request,'index.html',locals())
    else:
        msg='username or pwd is error'
        return render(request,'login.html',locals())

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index Page</title>
</head>
<body>
如果用户已经登录,则current_user变量有值,if判断为真,会打印便令current_user的值,为当前登录的用户名
如果用户没有登录,则current_user变量无值,if判断为假,会打印a标签要求用户先登录
{% if current_user %}
    <p>current user is : {{ current_user }} </p>
{% else %}
    <p><a href="/login/">please login</a></p>
{% endif %}
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
</head>
<body>

<form action="" method="POST">  
    {% csrf_token %}
    <p>username: <input type="text" name="name"></p>
    <p>pwd: <input type="password" name="pwd"></p>
    <p><input type="submit" value="submit"></p>
</form>
输错账号密码的时候提示
<p style="color: red">{{ msg }}</p>
</body>
</html>

其他重要标签:

1.autoscape:自动转义开关,控制自动转义是否可用,参数是on或者off,用法如下:
{% autoescape on %}
    {{ body }}
{% endautoescape %}

2.comment:注释
在{% comment %}和{% endcomment %}之间的内容会被忽略,
注意:comment标签不能嵌套使用

3.csrf_token:这个标签用于跨站请求伪造保护。常用于为form表单提供csrf令牌
<form action="" method="POST">  
    {% csrf_token %}
    <p>username: <input type="text" name="name"></p>
    <p>pwd: <input type="password" name="pwd"></p>
    <p><input type="submit" value="submit"></p>
</form>
具体工作原理:
3.1:在GET请求到form表单的时候,标签{% csrf_token %}会被渲染成一个隐藏的input标签,该标签包含了由服务端生成的一串随机字符串,如<input type="hidden" name="csrfmiddlewaretoken" value="dshjarbk...349">
3.2:在使用form表单提交POST请求时,会提交上面的随即字符串,服务端在接受到该POST请求时会对比该随机字符串,对比成功则处理该POST请求,否则拒绝,以此来确定客户端的身份。

4. debug 输出全部的调试信息,包括当前上下文和导入的模块 5. filter : 通过一个或者多个过滤器对内容进行过滤,需要结束标签endfilter eg: {% filter force_escape|lower %} This text will be HTML-escaped, and will appear in all lowercase. {% endfilter %} 6. firstof:输出第一个不为False的参数,如果传入的所有变量都为False,则什么也不输出 eg: {% firstof var1 var2 var3 %} 等价于: {% if var1 %} {{ var1 }} {% elif var2 %} {{ var2 }} {% elif var3 %} {{ var3 }} {% endif %} 当然也可以用一个默认字符串作为输出以防止传入的所有变量都是False: {% firstof var1 var2 var3 "fallback value" %} 该标签会自动转义变量值。您可以使用以下方法禁用自动转义 {% autoescape off %} {% firstof var1 var2 var3 "
<strong>fallback value</strong>" %} {% endautoescape %} 如果仅仅转义某一些变量,则可以使用: {% firstof var1 var2|safe var3 "<strong>fallback value</strong>"|safe %} 7. ifchanged:检查一个值是否在上一次的迭代中被改变了 {% ifchanged %}标签通常用在循环里。它有两个用处: 检查已经渲染过的内容的当前状态。并且只会显示发生改变的内容。例如,以下的代码是输出days的列表项,不过它只会输出被修改过月份的项: <h1>Archive for {{ year }}</h1> {% for date in days %} {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %} <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a> {% endfor %} 如果标签内有多个值时,则会比较每一个值是否与上一次不同。例如,以下显示每次更改时的日期,如果小时或日期已更改,则显示小时: {% for date in days %} {% ifchanged date.date %} {{ date.date }} {% endifchanged %} {% ifchanged date.hour date.date %} {{ date.hour }} {% endifchanged %} {% endfor %} ifchanged标记也可以采用可选的{% else %}将显示值没有改变的情况: {% for match in matches %} <div style="background-color: {% ifchanged match.ballot_id %} {% cycle "red" "blue" %} {% else %} gray {% endifchanged %} ">{{ match }}</div> {% endfor %} 8. load:加载自定义模板标签 下面的模板将会从somelibrary和package包中的otherlibrary中载入所有已经注册的标签和过滤器: {% load somelibrary package.otherlibrary %} 还可以使用from参数从库中选择性加载单个过滤器或标记 {% load foo bar from somelibrary %} 9. lorem作用: 这个标签是用来在模版中提供文字样本以供测试用的。使用场景是什么? 比如你要写个demo,里面要有一大段的文字和篇章,你不可能真的去写一篇文章吧?如果懒得去网上COPY,又不愿意使用一堆毫无意义杂乱的乱码,那么使用这个方法,可以帮你自动填充一些可以阅读的内容。 用法: {% lorem [count] [method] [random] %} 可以使用零个,一个,两个或三个参数。 这些参数是: count :一个数字(或变量),其中包含要生成的段落或字数(默认值为1)。 method:HTML中使用p标签、还是w标签、还是b标签,决定文本格式。默认是“b”。 random:如果给出的话,random这个词在生成文本时不会使用公共段落。 eg: {% lorem %}将输出常见的“lorem ipsum”段落。 {% lorem 3 p %}输出常用的“lorem ipsum”段落和两个随机段落,每段包裹在HTML`<p>`标签中。 {% lorem 2 w random %}将输出两个随机拉丁字。 10. now:显示当前的日期或时间。可以指定显示的格式。 例如: It is {% now "jS F Y H:i" %} 下面的例子中,“o”和“f”都被反斜杠转义: It is the {% now "jS \o\f F" %} 这将显示为“It is the 4th of September” 还可以使用语法{% now “Y” as current_year %}将输出存储在变量中 {% now "Y" as current_year %} {% blocktrans %}Copyright {{ current_year }}{% endblocktrans %} 11. regroup:对象间共有的属性重组列表。 eg: cities = [ {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'}, {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'}, {'name': 'New York', 'population': '20,000,000', 'country': 'USA'}, {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'}, {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'}, ] 可以使用{% regroup %}标签来给每个国家的城市分组: {% regroup cities by country as country_list %} <ul> {% for country in country_list %} <li>{{ country.grouper }} <ul> {% for city in country.list %} <li>{{ city.name }}: {{ city.population }}</li> {% endfor %} </ul> </li> {% endfor %} </ul> 输出: India Mumbai: 19,000,000 Calcutta: 15,000,000 USA New York: 20,000,000 Chicago: 7,000,000 Japan Tokyo: 33,000,000 总结:通过country属性重新分组cities列表,并将结果保存在country_list中 country_list的每个元素是具有两个字段的namedtuple()的实例: 1.grouper - 分组的项目(例如,字符串“India”或“Japan”) 2.list - 此群组中所有项目的列表(例如,所有城市的列表,其中country ='India') 12. spaceless:作用:删除HTML标签之间的空白,包括制表符和换行 用法示例: {% spaceless %} <p> <a href="foo/">Foo</a> </p> {% endspaceless %} 这个示例将返回下面的HTML: <p><a href="foo/">Foo</a></p> 仅会删除tags之间的空格,不会删除标签和文本之间的。下面的例子中,Hello周围的空格不会被删除: {% spaceless %} <strong> Hello </strong> {% endspaceless %} 13. templatetag:输出用于构成模板标签的语法字符 由于模板系统没有“转义”的概念,无法在HTML中使用‘\’转义出类似{%的字符。为了显示模板标签本身,必须使用{% templatetag %}标签,并添加相应的参数: openblock:{% closeblock: %} openvariable: {{ closevariable: }} openbrace :{ closebrace: } opencomment: {# closecomment: #} 例如: {% templatetag openblock %} url 'entry_list' {% templatetag closeblock %} 14. verbatim:禁止模版引擎在该标签中进行渲染工作。 常见的用法是允许与Django语法冲突的JavaScript模板图层工作,如下: {% verbatim %} {{if dying}}Still alive.{{/if}} {% endverbatim %} 15. widthratio:为了创建柱状形图,此标签计算给定值与最大值的比率,然后将该比率应用于常量 如下: <img src="bar.png" alt="Bar" height="10" width="{% widthratio this_value max_value max_width %}" /> 如果this_value是175,max_value是200,并且max_width是100,则上述示例中的图像将是88像素宽(因为175 / 200 = .875; .875 * 100 = 87.5,四舍五入入为88) 16. with:为一个复杂的变量起别名,如果变量的值来自数据库,在起别名的时候只需要使用别名即可,无需每次都向数据库中发送请求来重新获取变量的值 {% with li.1.upper as v %} {{ v }} {% endwith %}

第四:自定义过滤器和标签

如果内置过滤器和标签无法满足我们需求的时候,我们可以自定义标签和过滤器,如下

1.在settings.py中找到该列表,然后加以配置

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01', #添加当前的app的名字
]

2.在目录app01下面创建子目录templatetags(目录名字是固定的)

3.在templatetags新建任意py文件,如my_tags.py, 在该文件中自定义过滤器或者标签,如下:

from django import template
register = template.Library()

#1.custom filter
@register.filter
def my_multi_filter(v1,v2): #自定义的过滤器只能定义最多两个参数,针对{{ value1 | filter_multi:value2}},参数传递为v1=value1,v2=value2
    return v1 * v2

#2.custom tag
@register.simple_tag
def my_multi_tag(v1,v2): #自定义的标签可以定义多个参数
    return v1 * v2

#3.custom tag extend -->mark_safe
#内置的标签safe来让标签内容有语法意义,如果我们想让自定义标签处理的结果也有语法意义,则不能使用内置标签safe了,需要使用mark_safe,可以实现与内置标签safe同样的功能
from django.utils.safestring import mark_safe

@register.simple_tag
def my_input_tag(id,name):
    res = "<input type='text' id='%s' name='%s'/>" %(id,name)
    return mark_safe(res)

4.自定义过滤器或者标签以后必须重启django才能生效

5.自定义标签和过滤器的使用

urls.py

from django.contrib import admin
from django.urls import include,path,re_path,register_converter
from app01 import views


urlpatterns = [
    re_path(r'ylqh',views.ylqh),
]

views.py

from django.shortcuts import render,HttpResponse
from django.shortcuts import reverse
from django.shortcuts import redirect
import datetime
# Create your views here.
from django.views import View
def ylqh(request):
    salary=10
    return render(request,'ylqh.html',locals())

ylqh.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
</head>
<body>
<hr>

<!--必须先加载存在自定义过滤器和标签的文件-->
{% load my_tags %}

<!--经过过滤器处理后的值为120-->
{{ salary | my_multi_filter:12 }}

<hr>
<!--经过过滤器处理后的值为2-->
{% my_multi_tag 1 2 %}

<hr>
<!--结果为一个input标签,该标签的属性id='inp1' name="username"-->
<!--注意:input的属性均为字符串类型,所以my_input_tag后的两个值均为字符串类型-->
{% my_input_tag "inp" "username" %}

<hr>
<--对比自定义标签和自定过滤器-->
<!--自定义过滤器只能传递两个参数,而自定义标签可以传递多个参数-->
<!--过滤器可以用if判断,而标签不能-->
{% if salary|my_multi_filter:30 > 200 %}
    <p>great</p>
{% else %}
    <p>bad</p>
{% endif %}

</body>
</html>

第五:模板的导入和继承

在实际的工作中,模版文件彼此之间可能会有大量冗余代码,为此django提供了专门的语法来解决这个问题,主要围绕三种标签的使用:include标签,extends标签,block标签,详解如下:

5.1 模版的导入之include标签

作用:在一个模板文件中,引入或者重用另一个模板文件的内容
{% include '模版名称' %}

示例:把广告栏写道专门的文件里ylqh.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
</head>
<body>
<div class="adv">
    <div class="panel paanel-default">
        <div class="panel-heading">
            <h3 class="panel-title">Panel title</h3>
        </div>
        <div class="panel-body">
            Panel content
        </div>
    </div>
    <div class="panel paanel-danger">
        <div class="panel-heading">
            <h3 class="panel-title">Panel title</h3>
        </div>
        <div class="panel-body">
            Panel content
        </div>
    </div>
    <div class="panel paanel-warning">
        <div class="panel-heading">
            <h3 class="panel-title">Panel title</h3>
        </div>
        <div class="panel-body">
            Panel content
        </div>
    </div>

</div>
</body>
</html>

base.html文件中用include标签引入ylqh.html文件的内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index Page</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
    <style>
        *{
            margin: 0;
            padding: 0;
        }

        .header{
            height: 50px;
            width: 100%;
            background-color: black;
        }
    </style>
</head>
<body>
<div class="header"></div>
<div class="container">
    <div class="row">
        <div class="col-md-3">
          <!--在base.html中引入ylqh.html文件的内容-->
            {% include "ylqh.html" %}
        </div>
        <div class="col-md-9"></div>
    </div>
</div>
</body>
</html>

5.2 模板的继承和派生之extends标签、block标签

作用:在一个模版文件中,引入或者重用另一个模版文件的内容
{% extends "模版名称" %}
也就是说include有的功能extends全都有,但是extends可以搭配一个block标签,用于在继承的基础上定制新的内容。

示例:

django模版引擎中最复杂并且最强大的部分就是模版继承了,我们以先创建一个基本的“骨架”模版,它包含我们站点中的全部元素,并且可以定义多处blocks,例如我们创建base.html内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {% block title %}
            title name
        {% endblock %}
    </title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
    <style>
        *{
            margin: 0;
            padding: 0;
        }

        .header{
            height: 50px;
            width: 100%;
            background-color: #919191;
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
<div class="header"></div>
<div class="container">
    <div class="row">
        <div class="col-md-3">
            <div class="list-group">
                {% block sidebar %}
                    <a href="#" class="list-group-item active">服装城</a>
                    <a href="#" class="list-group-item">美术馆</a>
                    <a href="#" class="list-group-item">超市</a>
                    <a href="#" class="list-group-item">全球购</a>
                    <a href="#" class="list-group-item">闪购</a>
                    <a href="#" class="list-group-item">团购</a>
                {% endblock %}
            </div>
        </div>
        <div class="col-md-9"></div>
            {% block content  %}
                base.html context
            {% endblock %}
    </div>
</div>
</body>
</html>

模板base.html定义了一个可以用于两列排版页面的简单的HTML骨架,我们新建子模板index.html的主要工作就是继承base.html,然后填充或者覆盖其内部的blocks

<!DOCTYPE html>
{% extends "base.html" %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index Page</title>
</head>
<body>

<!--用心内容完全覆盖父内容-->
{% block title %}
    index page dd
{% endblock %}

{% block sidebar %}
<!--    该变量会将父模板中sidebar中原来的内容继承过来,然后我们可以再此基础上新增,否则就是纯粹地覆盖-->
    {{ block.super }}
<!--    在继承父模板内容的基础上新增的标签-->
    <a href="#" class="list-group-item">拍卖会</a>
    <a href="#" class="list-group-item">金融市场</a>
{% endblock %}

{% block content %}
<!--    用新内容完全覆盖了父模板内容-->
    <p>index page context </p>
{% endblock %}
</body>
</html>

通过django访问index.html看到内容如下(block标签的内容都完成了替换或者更新)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        index page dd
    </title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
    <style>
        *{
            margin: 0;
            padding: 0;
        }

        .header{
            height: 50px;
            width: 100%;
            background-color: #919191;
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
<div class="header"></div>
<div class="container">
    <div class="row">
        <div class="col-md-3">
            <div class="list-group">
               <!--    该变量会将父模板中sidebar中原来的内容继承过来,然后我们可以再此基础上新增,否则就是纯粹地覆盖-->
                    <a href="#" class="list-group-item active">服装城</a>
                    <a href="#" class="list-group-item">美术馆</a>
                    <a href="#" class="list-group-item">超市</a>
                    <a href="#" class="list-group-item">全球购</a>
                    <a href="#" class="list-group-item">闪购</a>
                    <a href="#" class="list-group-item">团购</a>
                    <!--    在继承父模板内容的基础上新增的标签-->
                    <a href="#" class="list-group-item">拍卖会</a>
                    <a href="#" class="list-group-item">金融市场</a>
            </div>
        </div>
        <div class="col-md-9"></div>
        <!--    用新内容完全覆盖了父模板内容-->
         <p>index page context </p>
    </div>
</div>
</body>
</html>

总结:

1. 标签extends必须放在行首,base.html中block越多可执行性越强

2. include仅仅只是完全引用其他模板问及那,而extends却可以搭配block在引用的基础上进行扩写。

3. 变量{{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖

4. 为了提高可读性,我们可以给标签{% endblock %}起一个名字。例如:

{% block content %}
    ...
{% endblock content %}

5.在一个模板中不能出现重名的block标签。

第六:静态文件

 我们在编写模板文件的时候,需要大量引用css,js,图片等静态文件,如果我们将这些文件在服务端存放的路径固定写死那么将非常不利于后期的扩展,我们可以按照如下方式解决:

1.setting.py

STATIC_URL = '/static/'
#增加如下代码:获取静态文件在服务端的绝对路径
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'statics')
]

2.在项目根目录下新增文件夹statics,为了方便管理,可以在static下新建文件夹css,js,img等静态文件。

3.新建模版文件ylqh.html,在该文件中对静态文件的引用如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
    <link rel="stylesheet" href="/static/css/my.css">
</head>
<body>

<img src="/static/img/header.png" alt="">
<script src="/static/js/jquery-3.3.1.min.js"></script>
<script src="/static/js/my.js"></script>

</body>
</html>

综上,在配置晚setting.py后,所有的静态文件路径都可以采用别名/static/ 作为起始,这在一定程度上会有利于程序的扩展性,但是如果我们在项目后期维护时,连/static/这个值都需要改,那就意味所有模板文件中也都需要跟着更改了,扩展性依然很差,为此,django在一个名为 static.py的文件中定义了标签static,get_static_prefix,二者都可以解决该问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
   必须先加载文件static.py
    {% load static %}
   此处的static是一个定义在static.py中的标签,名字与文件名一样,不要搞混
    <link rel="stylesheet" href="{% static 'css/my.css' %}">
</head>
<body>

<img src="/static/img/header.png" alt="">

{% load static %}
<script src="/static/js/jquery-3.3.1.min.js"></script>
<script src="/static/js/my.js"></script>

</body>
</html>

解释:标签static会接受传入的参数,然后根据settings.py中变量STATIC_URL的值拼接出一个完整的路径,如果STATIC_URL='/static/',那么href=“{% static 'css/my.css'%}” 会被渲染成href=“/static/css/my.css”,如果STATIC_URL=‘/static_test/’,那么href=“{% static 'css/my.css' %}”会被渲染成href=“/static123/css/my.css/”.

同时,标签get_static_prefix也可以完成同样的效果,只不过用法不同,我们不能为标签get_static_prefix进行传递参数,因为标签get_static_prefix代表的只是setting.py中STATIC_URL的值,所以我们需要做的是在get_static_prefix的基础上进行自动拼接路径。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login page</title>
<!--   必须先加载文件static.py-->
    {% load static %}
<!--   此处使用标签get_static_prefix拼接路径-->
    <link rel="stylesheet" href="{% get_static_prefix  %}css/my.css">
</head>
<body>

<img src="{% get_static_prefix  %}img/header.png" alt="">

{% load static %}
<script src="{% get_static_prefix  %}js/jquery-3.3.1.min.js"></script>
<script src="{% get_static_prefix  %}js/my.js"></script>

</body>
</html>

如果STATIC_URL = '/static/',那么href=“{% get_static_prefix %}css/my.css”,其他的也是一样的。

原文地址:https://www.cnblogs.com/ylqh/p/11803944.html