• Django——模板基础


    每一个Web框架都需要一种很便利的方法用于动态生成HTML页面。 最常见的做法是使用模板。

    模板包含所需HTML页面的静态部分,以及一些特殊的模版语法,用于将动态内容插入静态部分。

    说白了,模板层就是如何往HTML文件中填入动态内容的系统。

    模板的设计实现了业务逻辑view与显示内容template的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用。

     1.配置引擎

    Django可以配置一个或多个模板引擎(语言),也可以不用引擎。

    Django自带一个称为DTL(Django Template Language )的模板语言,以及另外一种流行的Jinja2语言(需要提前安装,pip install Jinja2)

    如果使用默认引擎,也不用配置什么,详细的配置,这里不做赘述,可以参考这个博客http://www.liujiangblog.com/course/django/144,或官方文档(英文允许的话)。

    2模板语法—变量

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

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

    变量的命名包括任何字母数字以及下划线("_")的组合。点(".")也有可能会在变量名中出现,不过它有特殊的含义。最重要的是,变量名称中不能有空格或标点符号。

    当模版系统遇到点("."),它将以这样的顺序查询这个圆点具体代表的功能:

    • 字典查询(用于字典)
    • 属性或方法查询(用于类)
    • 数字索引查询(用于列表或元组)

    如果你使用的变量不存在,模版系统将插入string_if_invalid选项的值,默认设置为''(空字符串)。

    示例:

    视图views.py

    class Book(object):
        def __init__(self, title):
            self.title=title
    
    
    def test(request):
        nums=[10, 11, 12]
        info={'name':'Eric'}
        book=Book('长得帅如何与人相处')
        context={'nums':nums, 'info':info, 'book':'book'}
        return render(request, 'test.html', context)
    View Code

    模板test.html

    <body>
    <h3>书的编号:{{ nums.0 }}</h3>
    <h3>书的作者:{{info.name }}</h3>
    <h3>书的名字:{{ book.title }}</h3>
    </body>
    View Code

     注意:句点符也可以用来引用对象的方法(无参数方法):

    <h3>作者:{{ info.name.upper }}</h3>

    3过滤器

    因为过滤器紧挨着变量,所以先说过滤器

    过滤器看起来是这样的:{{ name|lower }}。使用管道符号(|)来应用过滤器。该过滤器将文本转换成小写。

    一些过滤器带有参数,过滤器参数包含空格的话,必须用引号包起来。例如,使用逗号和空格去连接一个列表中的元素,你需要使用{{ list|join:", " }}

    django内置的过滤器有很多,列举几个常用的:

    default

    如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。

    {{ value|default:"nothing" }}

    length

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

    {{ value|length }}
    # 如果value是['a', 'b', 'c', 'd'],那么输出4。

    slice

    返回列表的一部分。也就是切片,与Python的列表切片相同的语法。

    {{ some_list|slice:":2" }}
    # 如果some_list是['a', 'b', 'c'] ,输出将为['a', 'b']。

    truncatechars

    如果字符串包含的字符总个数多于指定的字符数量,那么会被截断掉后面的部分。截断的字符串将以“...”结尾。

    {{ value|truncatechars:9 }}
    # 如果value是Joel is a slug,输出为Joel i...。

    date

    根据给定格式对一个日期变量进行格式化。

    # 如果 value=datetime.datetime.now()
    {{ value|date:"Y-m-d" }}

    safe

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

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

    关于自动转义,我们后面再说。

    4.标签

    标签看起来像是这样的: {% tag %}

    标签比变量复杂得多,有些用于在输出中创建文本,有些用于控制循环或判断逻辑,有些用于加载外部信息到模板中供以后的变量使用。

    一些标签需要开始和结束标签(即 {% 标签 %} ... 标签 内容 ... {% ENDTAG %})。

    同样,列举几个常用的:

    for标签

    # 循环对象中的每一个元素
    <ul>
    {% for athlete in athlete_list %}
        <li>{{ athlete.name }}</li>
    {% endfor %}
    </ul>
    
    # 如果循环对象points的每个元素都是(x,y)这样的二元元组,可以像以下面一样输出
    {% for x, y in points %}
        There is a point at {{ x }},{{ y }}
    {% endfor %}
    
    要访问一个字典中的键值,这个方法同样有用:
    {% for key, value in data.items %}
        {{ key }}: {{ value }}
    {% endfor %}
    View Code

    下面是Django为for标签内置的一些属性,可以当作变量一样使用{{ }}在模版中使用。

    • forloop.counter:循环的当前索引值,从1开始计数;常用于生成一个表格或者列表的序号!
    • forloop.counter0:循环的当前索引值,从0开始计数;
    • forloop.revcounter: 循环结束的次数(从1开始)
    • forloop.revcounter0 循环结束的次数(从0开始)
    • forloop.first:判断当前是否循环的第一次,是的话,该变量的值为True。我们经常要为第一行加点特殊的对待,就用得上这个判断了,结合if。
    • forloop.last:如果这是最后一次循环,则为真
    • forloop.parentloop:对于嵌套循环,返回父循环所在的循环次数。某些场景下,这是个大杀器,能解决你很多头疼的问题。

    for ... empty

    for标签带有一个可选的{% empty %}从句,以便在循环对象是空的或者没有被找到时,可以有所操作和提示。

    <ul>
    {% for athlete in athlete_list %}
        <li>{{ athlete.name }}</li>
    {% empty %}
        <li>Sorry, no athletes in this list.</li>
    {% endfor %}
    </ul>
    View Code

    if标签

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

    if标签可以使用not,and或or来测试布尔值

    if标签允许使用这些操作符:==!=<><=>=innot inisis not

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

    include

    加载指定的模板并以标签内的参数渲染。这是一种引入别的模板的方法,include类似Python的import。

    {% include "foo/bar.html" %}        # 将子模版渲染并嵌入当前HTML中

    url

    这是路由在模板层面反向解析用到的标签,返回与给定视图和可选参数匹配的绝对路径引用(不带域名的URL)

    {% url 'some-url-name' v1 v2 %}
    # 第一个参数是url()的名字,其他参数是可选的并且以空格隔开,这些值会在URL中以参数的形式传递

    如果使用urlconf的名称空间网址,通过冒号指定完全名称,如下所示:

    {% url 'myapp:view-name' %}

    with

    使用一个简单地名字缓存一个复杂的变量,当你需要使用一个代价较大的方法(比如访问数据库)很多次的时候这是非常有用的。

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

    csrf_token

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

    5.自定制标签、过滤器

    Django为我们提供了自定义的机制,可以通过使用Python代码,自定义标签和过滤器来扩展模板引擎,然后使用{% load %}标签。

    5.1配置准备

    1.将要增加自定义标签的app在INSTALLED_APPS中注册,否则django无法找到自定义的标签。

    2.在app中新建一个templatetags(名字固定,不能变,只能是这个),和views.py、models.py等文件处于同一级别目录下。这是一个包!不要忘记创建__init__.py文件以使得该目录可以作为Python的包。并在该包下创建了一个名为mytags.py的文件。

    3.要在模块内自定义标签,首先,这个模块必须包含一个名为register的变量,它是template.Library的一个实例,所有的标签和过滤器都是在其中注册的。 所以把如下的内容放在mytags.py文件顶部:

    from django import template
    
    register = template.Library()

    5.2自定义过滤器

    1.  自定义过滤器实际上就是写一个函数
    2. django会将过滤器前的值传入该函数
    3. 函数完成后,需要进行注册register

    因为第二步django已经帮我们完成,所以我们实际上只需要自己完成第一步和第三步

    示例:定义一个自动省略字符的过滤器

    # mytags.py
    
    from django import template
    
    register = template.Library()
    
    
    @register.filter(name='truncate_char')        # 注册过滤器的装饰器,name属性可以省略
    def truncate_char(value):       # 定义过滤器的函数
        if len(value) > 20:
            return value[0:20]+'...'
        else:
            return value
    View Code

    然后在模板页面装载使用

    {% load mytags %}     装载自定义过滤器
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {{ '超过20个字符后,将后面的字符省略,没超过20个字符,则可以显示全部'|truncate_chars }}
    </body>
    </html>
    View Code

    5.3自定义标签

    自定义标签相对于自定义过滤器来说要复杂很多,因为自定义标签可以做任何事情!

    自定义标签分为很多类型

    1. 简单标签  Simple tags
    2. 内含标签  Inclusion tags
    3. 分配标签  Assignment tags

    5.3.1简单标签

    import datetime
    from django import template
    
    register = template.Library()
    
    @register.simple_tag
    def current_time(format_string):    # 传入一个时间格式
        return datetime.datetime.now().strftime(format_string)     # 返回当前时间

    Library.simple_tag(takes_context=True),takes_context=True参数可以让我们访问模板的当前环境上下文,即将当前环境上下文中的参数和值作为字典传入函数中的一个名为context的参数

    @register.simple_tag(takes_context=True)
    def current_time(context,fromat_string):
        timezone = context['timezone']      # 接收上下文参数
        return your_get_current_time_method(timezone, format_string)

    当使用take_context=True时,函数的第一个参数必需为context。也可以使用name参数对函数进行重命名。

    5.3.2内含标签

    这种类型的标签可以被其他模板进行渲染,然后将渲染结果输出

    Library.inclusion_tag()支持take_context=True,用法类似Library.simple_tag()

    from django import template
    register = template.Library()
    
    @register.inclusion_tag('result.html')
    def tset():
        a=['first', 'second', 'third']
        return {'choices': a}

    result.html

    <ul>
    {% for choice in choices %}
        <li> {{ choice }} </li>
    {% endfor %}
    </ul>

    test.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {% load mytags %}      # 装载自定义模块
    {% test %}      # 导入标签
    </body>
    </html>
    View Code

    5.3.3分配标签

    类似于简单标签,但并不会输出结果,可以使用 as 关键字将结果赋给一个参数。

    @register.assignment_tag
    def get_current_time(format_string):
        return datetime.datetime.now().strftime(format_string)
    {% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
    <p>The time is {{ the_time }}.</p>

    6.模板继承

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

    模板继承和类的继承含义是一样的,主要是为了提高代码重用,减轻开发人员的工作量。

    父模板

    如果发现在多个模板中某些内容相同,那就应该把这段内容定义到父模板中。

    block标签:用于在父模板中预留区域,留给子模板填充差异性的内容,名字不能相同。 为了更好的可读性,建议给endblock标签写上名字,这个名字与对应的block名字相同。父模板中也可以使用上下文中传递过来的数据。

    {% block 名称 %}
        预留区域,可以编写默认内容,也可以没有默认内容
    {% endblock %}

    子模板

    extends标签继承,写在子模板文件的第一行

    {% extends "父模板路径" %}

    子模版不用填充父模版中的所有预留区域,如果子模版没有填充,则使用父模版定义的默认值。
    填充父模板中指定名称的预留区域。

    {% block 名称 %}
    实际填充内容
    {{ block.super }}     # 用于保留父模板中block的内容
    {% endblock 名称 %}

    示例

    父模板:base.html

    <html>
    <head>
        <title>{{title}}</title>
    </head>
    <body>
        <h2>这是头</h2>
        <hr>
        {%block content%}
        这是内容,有默认值
        {%endblock content%}
        <hr>
        {%block foot%}
        {%endblock foot%}
        <hr>
        <h2>这是尾</h2>
    </body>
    </html>
    View Code

    子模板:test.html

    {% extends "base.html" %}
    
    {% block content %}
        两个黄鹂鸣翠柳
        我还没有女朋友
        {{ block.super }}
    {% endblock content %}
    
    {% block foot %}
        垂死病中惊坐起
        笑问客从何处来
    {% endblock foot %}
    View Code

    那么子模板的输出效果就是:

    <html>
    <head>
        <title>{{title}}</title>
    </head>
    <body>
        <h2>这是头</h2>
        <hr>
        两个黄鹂鸣翠柳
        我还没有女朋友
        这是内容,有默认值
        <hr>
        垂死病中惊坐起
        笑问客从何处来
        <hr>
        <h2>这是尾</h2>
    </body>
    </html>
    View Code

    注意:

    • 如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。
    • 在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
    • 如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中
    • 不能在一个模版中定义多个相同名字的 block 标签。
    终日不为以思,无益,不如学也
  • 相关阅读:
    15天学会jQuery
    android面试题-简答题(一)
    android面试题-选择填空(一)
    【Android进阶】Android面试题目整理与讲解
    Android 面试题(有详细答案)
    Android开发人员必备的10 个开发工具
    Android环境搭建
    到底如何区分什么是架构、框架、模式和平台 ?
    c#执行Dos命令
    C#打开Word
  • 原文地址:https://www.cnblogs.com/lymlike/p/11561551.html
Copyright © 2020-2023  润新知