Django之模板层的实现代码


Posted in Python onSeptember 09, 2019

在例子视图中返回文本的方式有点特别,即HTML被直接硬编码在Python代码之中。

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

尽管这种技术便于解释视图是如何工作的,但直接将HTML硬编码到你的视图里却并是一个好主意。让我们来看一下为什么:

  • 对页面设计进行的任何改变都必须对Python代码进行相应的修改。站点设计的修改往往比底层Python代码的修改要频繁得多,因此如果可以在不进行Python代码修改的情况下变更设计,将会方便很多。
  • Python代码编写和HTML设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同的部门)来完成。设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。
  • 程序员编写Python代码和设计人员制作模板两项工作过同时进行的额效率是最高的,远胜于让一个人等待另一个人完成对某个既包含Python又包含HTML的文件的编辑工作。

基于这些原因,将页面的设计和Python的代码分离开会更干净简洁更容易维护。我们可以使用Django的模板系统(Template System)来是现在这种模式,这就是本章要具体讨论的问题。

Python的模板:HTML代码 + 模板语法

def current_time(req):
  # ================================原始的视图函数
  # import datetime
  # now=datetime.datetime.now()
  # html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now

  # ================================django模板修改的视图函数
  # from django.template import Template,Context
  # now=datetime.datetime.now()
  # t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
  # #t=get_template('current_datetime.html')
  # c=Context({'current_date':str(now)})
  # html=t.render(c)
  #
  # return HttpResponse(html)

  #另一种写法(推荐)
  import datetime
  now=datetime.datetime.now()
  return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})

一、模板语法之变量

在Django模板中遍历复杂数据结构的关键是句点字符,语法:

{{var_name}}

views.py:

def index(request):
  import datetime
  s="hello"
  l=[111,222,333]  # 列表
  dic={"name":"yuan","age":18} # 字典
  date = datetime.date(1993, 5, 2)  # 日期对象

  class Person(object):
    def __init__(self,name):
      self.name=name

  person_yuan=Person("yuan") # 自定义类对象
  person_egon=Person("egon")
  person_alex=Person("alex")

  person_list=[person_yuan,person_egon,person_alex]

   return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})

template:

<h4>{{s}}</h4>
<h4>列表:{{ l.0 }}</h4>
<h4>列表:{{ l.2 }}</h4>
<h4>字典:{{ dic.name }}</h4>
<h4>日期:{{ date.year }}</h4>
<h4>类对象列表:{{ person_list.0.name }}</h4>
注:句点符也可以用来引用对象的方法(无参数方法):
<h4>字典:{{ dic.name.upper }}</h4>

二、模板之过滤器

语法:

{{obj|filter_name:param}}

default

如果一个变量是False后者为空,使用给定的默认值。否则,使用变量的值。例如:

{{ value|default:'nothing' }}

length

返回值的长度。它对字符串和列表都起作用。例如:

{{ value|length }}

如果value是 ['a', 'b', 'c', 'd'] ,那么输出的就是4.

filesizeformat

将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB' , '4.1 MB' , '102 bytes' , 等等)。例如:

{{ value|filesizeformat }}

如果value = 123456789,输出将会是117.7 MB。

date

如果value = datetime.datetime.now()

{{ value|date:"Y-m-d" }}

slice

如果value = "hello world"

{{ value|slice:"2:-1" }}

truncatechars

如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列("...")结尾。

参数:要截断的字符数

{{ value|truncatechars:9 }}

safe

Django的模板中会对HTML标签和JS语法等标签进行自动转义,原因显而易见这样是为了安全。但是有时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后他添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器"|safe"的方式告诉Django这段代码是安全的不必转义。比如:

value = "<a href=''>点击</a>"
{{ value|safe }}

三、模板之标签

标签看起来像是这样: {% tag %} 。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息的模板中。一些标签需要开开始和结束标签(例如 {% tag %} ...标签 内容... {% endtag %} )。

for标签

遍历每一个元素:

可以利用 {% for obj in list reversed %} 方向完成循环。

遍历一个字典:

{% for key,val in dic.items %}
  <p>{{ key }}:{{ val }}</p>
{% endfor %}

注:循环序号可以通过 {{ for|loop }} 显示

forloop.counter      # The current iteration of the loop (1-indexed)
forloop.counter0     # The current iteration of the loop (0-indexed)
forloop.revcounter    # The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0    # The number of iterations from the end of the loop (0-indexed)
forloop.first       # True if this is the first time through the loop
forloop.last       # True if this is the last time through the loop
for ... empty

for标签带有一个可选的 {% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。

{% for person in person_list %}
  <p>{{ person.name }}</p>

{% empty %}
  <p>sorry,no person here</p>
{% endfor %}

if 标签

{% if %} 会对一个变量求值,如果它的值是True(存在、不为空、且不是boolean类型的False值),对应的内容块会输出。

{% if num > 100 or num < 0 %}
  <p>无效</p>
{% elif num > 80 and num < 100 %}
  <p>优秀</p>
{% else %}
  <p>凑活吧</p>
{% endif %}

with 标签

使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵”的方法(比如访问数据库)很多次的时候是非常有用的。例如:

{% with total=business.employees.count %}
  {{ total }} employee{{ total|pluralize }}
{% endwith %}

csrf_token 标签

这个标签用于跨站请求伪造保护。

四、自定义标签和过滤器

1、在settings中的INSTALLED_APPS配置当前app,不然Django无法找到自定义的simple_tag。

2、在app中创建templatetags模块(模块名只能是templatetags)。

3、创建任意 .py 文件,如:my_tags.py。

from django import template
 from django.utils.safestring import mark_safe
 register = template.Library()  #register的名字是固定的,不可改变 
 @register.filter
 def filter_multi(v1,v2):
   return v1 * v2
 <br>
 @register.simple_tag
 def simple_tag_multi(v1,v2):
   return v1 * v2
 <br>
 @register.simple_tag
 def my_input(id,arg):
   result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
   return mark_safe(result)

4、在使用自定义simple_tag和filter的HTML文件中导入之前创建的my_tags.py。

{% load my_tags %}

5、使用simple_tag和filter(如何调用)

-------------------------------.html
 {% load xxx %}    
 # num=12
 {{ num|filter_multi:2 }} #24
 {{ num|filter_multi:"[22,333,4444]" }}
 {% simple_tag_multi 2 5 %} 参数不限,但不能放在if for语句中
 {% simple_tag_multi num 5 %}
注:filter可以用在if等语句后,simpe_tag不可以。
{% if num|filter_multi:30 > 100 %}
  {{ num|filter_multi:30 }}
{% endif %}

五、模板继承(extend)

Django模板引擎中最强大也是最复杂的部分就是模板继承了。模板继承可以让你创建一个基本的“骨架”模板,它包含你站点中的全部元素,并且可以定义能够被子模板覆盖的blocks.

通过从下面这个例子开始,可以容易地理解模板继承:

<!DOCTYPE html>
<html lang="en">
<head>
  <link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" />
  <title>{% block title %}My amazing site{%/span> endblock %}</title>
</head>

<body>
  <div id="sidebar">
    {% block sidebar %}
    <ul>
      <li><a href="/" rel="external nofollow" rel="external nofollow" >Home</a></li>
      <li><a href="/blog/" rel="external nofollow" rel="external nofollow" >Blog</a></li>
    </ul>
    {% endblock %}
  </div>

  <div id="content">
    {% block content %}{% endblock %}
  </div>
</body>
</html>

假设这个模板叫做 base.html,它定义了一个可以用于两列排版页面的简单HTML骨架。“字模板”的工作是用它们的内容填充的blocks。

在这个例子中,block标签定义了三个可以被子模板内容填充的block。block告诉模板引擎:子模板可能会覆盖掉模板中的这些位置。

子模板可能看起来是这样的:

{% extends "base.html" %}

{% block title %}My amazing blog{% endblock %}

{% block content %}
{% for entry in blog_entries %}
  <h2>{{ entry.title }}</h2>
  <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

extends标签是这里的关键。它告诉模板引擎,这个模板“继承”了另一个模板。当模板系统处理这个模板时,首先,它将定位父模板——在此例中,就是 base.html。

那时,模板引擎将注意到 base.html 中的三个block标签,并用子模板中的内容来替换这些block。根据blog_entries的值,输出可能看起来是这样的:

<!DOCTYPE html>
<html lang="en">
<head>
  <link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" />
  <title>My amazing blog</title>
</head>

<body>
  <div id="sidebar">
    <ul>
      <li><a href="/" rel="external nofollow" rel="external nofollow" >Home</a></li>
      <li><a href="/blog/" rel="external nofollow" rel="external nofollow" >Blog</a></li>
    </ul>
  </div>

  <div id="content">
    <h2>Entry one</h2>
    <p>This is my first entry.</p>

    <h2>Entry two</h2>
    <p>This is my second entry.</p>
  </div>
</body>
</html>

请注意,子模版并没有定义 sidebar block,所以系统使用了父模版中的值。父模版的 {% block %} 标签中的内容总是被用作备选内容(fallback)。这种方式使代码得到最大程度的复用,并且使得添加内容到共享的内容区域更加简单,例如,部分范围内的导航。

下面是使用继承的一些提示:

  • 如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。
  • 在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
  • 如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中。
  • If you need to get the content of the block from the parent template, the variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.

为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:

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

在大型模板中,这个方法帮你清楚地看到哪一个 {% block %} 标签被关闭了。

不能在一个模版中定义多个相同名字的 block 标签。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python获取一组汉字拼音首字母的方法
Jul 01 Python
微信跳一跳python代码实现
Jan 05 Python
基于Python log 的正确打开方式
Apr 28 Python
Python使用try except处理程序异常的三种常用方法分析
Sep 05 Python
在Qt5和PyQt5中设置支持高分辨率屏幕自适应的方法
Jun 18 Python
Python使用Pandas库实现MySQL数据库的读写
Jul 06 Python
python过滤中英文标点符号的实例代码
Jul 15 Python
Python如何调用JS文件中的函数
Aug 16 Python
python 并发编程 非阻塞IO模型原理解析
Aug 20 Python
关于Tensorflow使用CPU报错的解决方式
Feb 05 Python
python实现随机加减法生成器
Feb 24 Python
python实现文件分片上传的接口自动化
Nov 19 Python
Django模板语言 Tags使用详解
Sep 09 #Python
Python中turtle库的使用实例
Sep 09 #Python
Django之路由层的实现
Sep 09 #Python
python中web框架的自定义创建
Sep 08 #Python
python web框架中实现原生分页
Sep 08 #Python
python中open函数的基本用法示例
Sep 07 #Python
Python3显示当前时间、计算时间差及时间加减法示例代码
Sep 07 #Python
You might like
根德YB400的电路分析
2021/03/02 无线电
ThinkPHP中的关联模型注意点
2014/06/16 PHP
php获得客户端浏览器名称及版本的方法(基于ECShop函数)
2015/12/23 PHP
php在linux环境中如何使用redis详解
2020/12/15 PHP
javascript SocialHistory 检查访问者是否访问过某站点
2008/08/02 Javascript
用js实现判断当前网址的来路如果不是指定的来路就跳转到指定页面
2011/05/02 Javascript
formvalidator验证插件中有关ajax验证问题
2013/01/04 Javascript
JS实现时间格式化的方式汇总
2013/10/16 Javascript
js简单抽奖代码
2015/01/16 Javascript
JS实现5秒钟自动封锁div层的方法
2015/02/20 Javascript
javascript实现仿IE顶部的可关闭警告条
2015/05/05 Javascript
javascript中的previousSibling和nextSibling的正确用法
2015/09/16 Javascript
javascript RegExp 使用说明
2016/05/21 Javascript
点击按钮出现60秒倒计时的简单js代码(推荐)
2016/06/07 Javascript
AngularJS基础 ng-list 指令详解及示例代码
2016/08/02 Javascript
Angular.js自定义指令学习笔记实例
2017/02/24 Javascript
基于vue2实现上拉加载功能
2017/11/28 Javascript
swiper插件自定义切换箭头按钮
2017/12/28 Javascript
详解extract-text-webpack-plugin 的使用及安装
2018/06/12 Javascript
vue自定义指令用法经典实例小结
2019/03/16 Javascript
在vue项目实现一个ctrl+f的搜索功能
2020/02/28 Javascript
Python命名空间详解
2014/08/18 Python
浅谈Python类的__getitem__和__setitem__特殊方法
2016/12/25 Python
python将每个单词按空格分开并保存到文件中
2018/03/19 Python
pip 安装库比较慢的解决方法(国内镜像)
2019/10/06 Python
Pytorch之Tensor和Numpy之间的转换的实现方法
2020/09/03 Python
详解Python3.8+PyQt5+pyqt5-tools+Pycharm配置详细教程
2020/11/02 Python
Pycharm配置lua编译环境过程图解
2020/11/28 Python
HTML5页面直接调用百度地图API获取当前位置直接导航目的地的实现代码
2018/03/02 HTML / CSS
三星新西兰官网:Samsung新西兰
2019/03/05 全球购物
会计专业毕业生推荐信
2013/11/05 职场文书
2014年应届大学生毕业自我鉴定
2014/01/31 职场文书
公司合作协议范文
2014/10/01 职场文书
公司员工违纪检讨书
2015/05/05 职场文书
小学生法制教育心得体会
2016/01/14 职场文书
Python实现位图分割的效果
2021/11/20 Python