• Django 模版语法与使用


    Django 模版语法与使用

    目录

    django模板语言介绍 (摘自官方文档) 链接

    """
    Django模板语言
    Django的模板语言旨在在功能和易用性之间取得平衡。它让那些习惯使用HTML的人感到舒服。
    如果您对其他基于文本的模板语言(如Smarty 或Jinja2)有过接触,那么您应该对Django的模板感到宾至如归。
    
    哲学
    如果您有编程背景,或者习惯于将编程代码直接混合到HTML中的语言,那么您需要记住,
    Django模板系统不仅仅是嵌入到HTML中的Python。这是一种设计,模板系统用于表达,而不是程序逻辑。
    
    Django模板系统提供的标签功能类似于一些编程结构 如 if,布尔,for标签,循环标签等 - 但这些标签不是简单地作为相应的Python代码执行,
    模板系统不会执行任意Python表达式。默认情况下,仅支持下面列出的标记,过滤器和语法(您可以根据需要将自己的扩展添加到模板语言中)。
    
    哲学
    为什么使用基于文本的模板而不是基于XML的模板(如Zope的TAL)?我们希望Django的模板语言不仅可用于XML / HTML模板。
    在World Online,我们将其用于电子邮件,JavaScript和CSV。您可以将模板语言用于任何基于文本的格式。
    
    哦,还有一件事:让人类编辑XML是虐待狂!
    """
    

    什么是模板?

    模板只是一个文本文件。它可以生成任何基于文本的格式(HTML,XML,CSV等)。
    模板包含变量,这些变量在评估模板时将替换为值,而变量则包含控制模板逻辑的标记。
    只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板。
    

    模板语句的 注释

    模板语句的注释
    {#{{ '10'|add_str:'5 '}}#}  
    {#注释内容#}    
    

    变量 {{ 变量 }}

    • 变量:语法为 {{ }}:括号里加要渲染变量的变量值,变量名由字母数字和下划线组成。
    • 代码
    #views 文件函数
    def template_test(request):
        name = '钢蛋'
        age = 18
        hobby = ['唱', '跳', 'rap', '篮球']
        lis = []
        st = ''
        dic = {
            'name': '铁蛋',
            'age': 16,
            'hobby': hobby,
            'keys': 'xxxxx'
        }
        dic_2 = {}
        return render(request,'template_test.html',
     {'name':name_p,'age':age,'hobby':hobby,'lis':lis,'st':st,'dic':dic,'dic_2':dic_2})
    
    # 模板文件html页面
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>郭楷丰</title>
    </head>
    <body>
    {{ 啦啦啦啦啦 }}
    <p>
        {{ name }}
    </p>
    <p>
       {{ age }}
    </p>
    <p>
        {{ hobby }}
    </p>
    <p>
        {{ lis }}
    </p>
    <p>
        {{ st }}
    </p>
    <p>
        {{ dic }}
    </p>
    <p>
        {{ dic_2 }}
    </p>
    </body>
    </html>
    
    • 浏览器结果:

    img

    • 小结: {{ }}里填要渲染的变量,规范写法,两边用括号隔开 如 {{ 变量 }}, 后端没有传参的页面不显示
      img

    img

    点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。

    • 例子 代码 .索引 .key .属性 .方法
    #views 文件函数
    def template_test(request):
        lis = [1, 2, 3,4,5]
        dic = {"name": "黑蛋"}
    
        class Person(object):
            def __init__(self, name, age):
                self.name = name
                self.age = age
    
            def dream(self):
                return " 我 is {} age {}岁...".format(self.name,self.age)
    
        gangdan = Person(name="钢蛋", age=18)
        goudan = Person(name="狗蛋", age=17)
        tiedan  = Person(name="铁蛋", age=16)
    
        person_list = [gangdan, goudan, tiedan]
        return render(request, "template_test.html", {"lis": lis, "dic": dic, "person_list": person_list})
    
    # 模板文件html页面
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>郭楷丰</title>
    </head>
    <boby>
        <p>{{ lis.0 }}</p>   <!--取l中的第一个参数-->
        <p>{{ dic.name }}</p><!--取字典中key的值-->
        <p>{{ person_list.0.name }}</p><!--取对象的name属性-->
        <p>{{ person_list.0.dream }}</p><!--.操作只能调用不带参数的方法-->
    </boby>
    </html>
    
    • 小结:
    #注:当模板系统遇到一个(.)时,会按照如下的顺序去查询:
    1. 在字典中查询
    2. 属性或者方法
    3. 数字索引   # 索引不能为负数
    

    img

    img

    Tags 标签 {% %} 表示逻辑相关的操作

    • 代码例子
    {% for foo in lis %}
    <!--for循环-->
        {% if  %}
        <!--if判断-->
        {% elif %}
        <!--elif判断-->
        {% endif %}
        <!--if闭合符-->
        {% else %}
        <!--else判断不成立执行-->
    {% endfor %}
    <!--for循环闭合符-->
    
    <!--应用 模板html代码-->
    <form action="" method="post">
        <label for="inputEmail3" class="col-sm-2 control-label">书名: </label>
        <div class="col-sm-8">
            <input type="text" name="book_name" class="form-control" value="{{ edit_obj.title }}">
            <select name="pub_id" id="" class="btn btn-default  btn-sm">
                {% for foo in publishers %}
                {% if foo == edit_obj.pub %}
                <option selected value="{{ foo.pk }}"> {{ foo.name }}</option>
                {% else %}
                <option value="{{ foo.pk }}"> {{ foo.name }}</option>
                {% endif %}
                {% endfor %}
            </select>
        </div>
        <div class="text-center text-danger">{{ error }}</div>
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default">提交</button>
        </div>
    </form>
    
    <!--应用 python逻辑代码 #views 文件函数-->
    def edit_book(request):
        error = ''
        pk = request.GET.get('pk')
        edit_obj = models.Book.objects.filter(id=pk)
        if not edit_obj:
            return HttpResponse('要编辑的数据不存在')
        if request.method == 'POST':
            book_name = request.POST.get('book_name')
            if not book_name.strip():
                error = "书名不能为空"
            pub_id = request.POST.get('pub_id')
            if edit_obj[0].title == book_name and edit_obj[0].pub_id == int(pub_id):
                error = "未作修改"
            if not error:
                obj = edit_obj[0]
                obj.title = book_name
                obj.pub_id = int(pub_id)
                obj.save()
                return redirect('/book_list/')
        publishers = models.Publisher.objects.all()
        return render(request,'edit_book.html',{'edit_obj':edit_obj[0],'publishers':publishers,'error':error})
    
    • 执行效果

    img

    img

    • if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

    • js,python,模板语言的判断逻辑

      #python
      10>5>1  =》   10>5  and 5>1   true 
      
      #js
      10>5>1  =》   10>5  =》 true   =》   1>1  false
      
      #模板中  
      不支持连续连续判断,也不支持算数运算(过滤器)
      
    • 注意事项

    • Django的模板语言不支持连续判断,也不支持以下写法:

    {% if a > b > c %}
    ...
    {% endif %}
    #不支持算数运算 + - * /
    
    
    • Django的模板语言中属性的优先级大于方法
    def xx(request):
        d = {"a": 1, "b": 2, "c": 3, "items": "100"}
        return render(request, "xx.html", {"data": d})
    
    
    • 如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items并且还有默认的 d.items() 方法,此时在模板语言中:
    {{ data.items }}   默认会取d的items key的值。
    
    

    for循环可用的一些参数:

    Variable Description
    forloop.counter 当前循环的索引值(从1开始)
    forloop.counter0 当前循环的索引值(从0开始)
    forloop.revcounter 当前循环的倒序索引值(到1结束)
    forloop.revcounter0 当前循环的倒序索引值(到0结束)
    forloop.first 当前循环是不是第一次循环(布尔值)
    forloop.last 当前循环是不是最后一次循环(布尔值)
    forloop.parentloop 本层循环的外层循环
    • for ... empty

    #for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
    {% for person in person_list %}
        <p>{{ person.name }}</p>
    {% empty %}
        <p>sorry,no person here</p>
    {% endfor %}
    
    

    Filters 过滤器

    • 用来修改变量的显示结果, 语法: {{ value|filter_name:参数 }} ':' 左右没有空格没有空格没有空格

    • 设置除法除尽 divisibleby:参数

    img

    with 的使用

    • 定义一个中间变量(起个别名,只在with内部生效)
    #写法一
    {% with total=business.employees.count %}
        {{ total }} employee{{ total|pluralize }}
    {% endwith %}
    
    #写法二
    {% with business.employees.count as total %}
        {{ total }} employee{{ total|pluralize }}
    {% endwith %}
    
    

    img

    default 系统默认值

    {{ value|default:"nothing"}}
    如果value值没传的话就显示nothing
    注:TEMPLATES的OPTIONS可以增加一个选项:string_if_invalid:'找不到',可以替代default的的作用。
    (在配置文件settings.py设置)
    
    
    • 配置设置变量不传参显示值

    img

    • 页面效果

    img

    filesizeformat 文件大小人性化显示

    • 将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)例如:
    {{ value|filesizeformat }}
    如果 value 是 123456789,输出将会是 117.7 MB
    
    

    add "加"

    • 给变量加参数,字符串默认尝试转int类型,转不了就拼接
    {{ value|add:"2" }}
    value是数字4,则输出结果为6
    
    {{ value|add:"hello" }}
    value是数字666,则输出结果为666hello
    
    {{ first|add:second }}
    如果first是 [1,.2,3] ,second是 [4,5,6] ,那输出结果是 [1,2,3,4,5,6] 
    
    

    lower 小写

    {{ value|lower }}
    
    

    upper 大写

    {{ value|upper}}
    
    

    title 标题

    {{ value|title }}
    
    

    ljust 左对齐

    "{{ value|ljust:"10" }}"
    
    

    rjust 右对齐

    "{{ value|rjust:"10" }}"
    
    

    center 居中

    "{{ value|center:"15" }}"
    
    

    length 长度

    {{ value|length }}
    返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.
    
    

    slice 切片

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

    first 取第一个元素

    {{ value|first }}
    
    

    last 取最后一个元素

    {{ value|last }}
    
    

    join 使用字符串拼接列表

    • 同python的str.join(list)
    {{ value|join:" // " }}
    
    

    cut 移除value中所有的与给出的变量相同的字符串

    • 如果value为'i love you',那么将输出'iloveyou'.
    {{ value|cut:' ' }}
    
    

    truncatechars 按照字符截断 ...也计数

    • 如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾
    #参数:截断的字符数
    {{ value|truncatechars:9}}
    
    truncatewords 按照单词进行截断, 只针对英文(...)不计数,中文按字计算
    
    

    date 日期格式化

    #后端
    import datetime
    def mul(request):
        value = datetime.datetime.now()
        return render(request, 'mul.html',{'value':value})
    
    #模板语句
    {{ value|date:"Y-m-d H:i:s"}}   #显示格式 年-月-日 时:分:秒
    
    
    #后端
    import datetime
    def mul(request):
        now = datetime.datetime.now()
        return render(request, 'mul.html',{'now':now})
    
    #模板直接使用变量
    {{ now }}  #显示格式 June 19,2019,22:00 p.m.
    
    #时间格式和默认值一起使用
    {{ obj.next_date|date:"Y-m-d"|default:"暂无" }}
    
    
    • 页面效果

    img

    img

    img

    • 可格式化输出的字符: 点击查看
    • 改配置文件设置显示样式 (一劳永逸的解决办法)
    #settings.py文件设置
    USE_L10N = False  #更换为False
    
    DATETIME_FORMAT = 'Y-m-d H:i:s' #添加
    
    #也可以日期与时间分开设置  根据自己的需求设置
    DATE_FORMAT = 'Y-m-d'   
    TIME_FORMAT = 'H:i:s'
    
    

    img

    safe 防止xss攻击 作用 取消转义

    • 简单了解xss攻击
        XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,
    故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
        XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
    比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。
    这种类型的漏洞由于被骇客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。对于跨站脚本攻击,
    骇客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。
    
    
    • xss攻击流程

    img

    safe 主要作用

    #Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。
    但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,
    这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。
    为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
    
    
    • 正常情况下
    #页面代码:
    {% load my_tags %}
    {{ 'https://www.baidu.com/'|show:'百度' }}
    
    #自定过滤器代码
    @register.filter
    def show(url,name):
        return "<a href = '{}'>{}</a>".format(url,name)
    
    
    • 页面显示效果

    img

    • 过滤器函数 加is_safe = True 解除转义
    #自定过滤器代码
    @register.filter(is_safe = True)
    def show(url,name):
        return "<a href = '{}'>{}</a>".format(url,name)
    
    
    • 页面效果
      img
    • 模板语句中加 safe 解除转义
    #模板语句
    {% load my_tags %}
    {{ 'https://www.baidu.com/'|show:'百度'|safe }}
    
    
    • 页面效果
      img

    • 也可以导入模块实现这种效果

    img

    img

    自定义 filter

    • 当普通的内置过滤器,实现不了我们的开发需求,那我们可以自定义过滤器来实现功能
    自定义过滤器是只能带有一个或两个参数的Python函数:
    变量(输入)的值 - -不一定是一个字符串
    参数的值 - 这可以有一个默认值,或完全省略
    例如,在过滤器{{var | foo:“bar”}}中,过滤器foo将传递变量var和参数“bar”。
    自定义filter代码文件摆放位置:
    app01/
        __init__.py
        models.py
        templatetags/  # 在app01下面新建一个package package
            __init__.py
            app01_filters.py  # 建一个存放自定义filter的py文件
        views.py
    
    

    自定义过滤器流程

    • 1 在app下创建一个名为templatetags的python包
    #注意 
    在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag
    
    (模块名只能是templatetags)
    
    
    • 2 在python中创建py文件,文件名可以自定义 如:(my_tags.py)
    • 3 在py文件中写:
    from django import template
    
    register = template.Library()  #固定写法,不可改变
    
    
    • 4 写函数+装饰器
    @register.filter  #过滤器
    def add_str(value, arg):  # 最多有两个
        return '{}-{}'.format(value, arg)
    
    
    • 5 写页面代码 在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py
    {% load my_tags %}   #先导入我们自定义那个文件 my_tags
    {{ name|add_str:age }}   #参数只能是两个,一个参数是变量name ,一个是参数是后面的那个参数age
    
    
    • 执行结果

    img

    • 自定义乘法过滤器 multioly

    #过滤器函数
    @register.filter
    def multiply1(value,arg):
        return value * arg
        
    #模板语句
    {% load my_tags %}
    <p>{{ 6|multiply1:'6' }}</p>
    <p>{{ 6|multiply1:6 }}</p>
    <p>{{ '10'|multiply1:5 }}</p>
    
    
    • 执行结果

    img

    img

    • 自定义除法过滤器 division

    #过滤器函数
    @register.filter
    def division(value,arg):
        return value / arg
    
    #模板语句
    {% load my_tags %}
    <p>{{ 6|division:6 }}</p>
    <p>{{ 6|division:1 }}</p>
    
    
    • 执行结果

    img

    • 自定义除法过滤器 add

    #过滤器函数
    @register.filter
    def add(value,arg):
        return value + arg   #可以这样写,但是转换不了会报错 int(value) + int(arg)
    
    #模板语句
    {% load my_tags %}
    <p>{{ 6|add:6 }}</p>
    <p>{{ 6|add:0 }}</p>
    
    <p>{{ '钢蛋g'|add:18 }}</p>
    
    
    • 执行结果

    img

    img

    • 自定义减法过滤器 subtraction

    #过滤器函数
    @register.filter
    def add(value,arg):
        return value - arg
    
    #模板语句
    {% load my_tags %}
    <p>{{ 6|add:6 }}</p>
    <p>{{ 6|add:0 }}</p>
    
    
    • 执行结果

    img

    自定义标签 simpletag

    • 与自定义过滤器区别,可以接受更多参数,使用标签引用{{% %}
    与自定义filter类似(也是在python包的templatetags文件下,创建此标签),只不过接收更灵活的参数。
    
    #simple_tag  代码
    @register.simple_tag(name="plus")
    def plus(a, b, c):
        return "{} + {} + {}".format(a, b, c)
    
    #使用simple tag  自定义标签 
    {% load app01_demo %}
    {# simple tag #}
    {% plus "1" "2" "abc" %}
        
        
    #例子  标签代码
    @register.simple_tag
    def join_str(*args, **kwargs):
        return '{} - {} '.format('*'.join(args), '$'.join(kwargs.values()))
    
    # 模板
    {% load my_tags %}
    {% join_str '1' '2' '钢蛋' k1='3' k2='4' %}    
    
    
    • 执行效果

    img

    自定义标签 inclusion_tag

    • 多用于返回html代码片段 (动态变量 分页)

    img

    img

    • app文件下 创建python包

    img

    • 包文件名必须为 templatetags

    img

    • 在templatetags里面创建任意 .py 文件

    img

    • 写函数

    img

    • html页面代码

      #分页显示代码
      <nav aria-label="Page navigation">
        <ul class="pagination">
          <li>
            <a href="#" aria-label="Previous">
              <span aria-hidden="true">&laquo;</span>
            </a>
          </li>
          {% for i in num %}
              <li><a href="#">{{ i }}</a></li>
          {% endfor %}
          <li>
            <a href="#" aria-label="Next">
              <span aria-hidden="true">&raquo;</span>
            </a>
          </li>
        </ul>
      </nav>
      
      
      #页面1
      {% load my_tags %}
      {% page 5 %}
      
      #页面2
      {% load my_tags %}
      {% page 1 %}
      
      
    • 显示效果

    img

    img

    img

    • 总结:

    自定义过滤器 filter 只能接受两个参数 调用的时候使用 {{ filter }}
    
    自定义标签  simpletag  与自定义过滤器区别,可以接受更多参数,使用标签引用{{%  %}
                                                
    自定义标签 inclusion_tag  多用于返回html代码片段,使用标签引用{{% %}                                   
    
    

    csrf_token 跨站请求伪造保护

    在页面的form表单里面写上{% csrf_token %}
    
    
    • 如图

    img

    img

    静态文件相关

    #作用 在配置文件找到静态文件别名,与文件地址进行拼接,这样别名改了,也不会影响,静态文件的导入
    
    {% load static %}
    <img src="{% static "images/hi.jpg" %}" alt="Hi!" />
    
    #引用JS文件时使用:
    {% load static %}
    <script src="{% static "mytest.js" %}"></script>
    
    #某个文件多处被用到可以存为一个变量
    {% load static %}
    {% static "images/hi.jpg" as myphoto %}
    <img src="{{ myphoto }}"></img>
    
    
    {% load static %}
     <link rel="stylesheet" href="{% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %}">
     <link rel="stylesheet" href="{% static '/css/dsb.css' %}">
    {% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %}  
    
    {% get_static_prefix %}   # 获取别名
    
    
    • 获取配置文件的 别名

    img

    img

    母版和继承

    什么是母版?

    普通的HTML页面 母版页用于处理html页面相同部分内容,避免出现冗余代码,减少重复html页面的编写,提高代码复用性,方便代码修改.
    
    

    继承写法

    #在子页面中在页面最上方使用下面的语法来继承母板。
    {% extends '母版文件名.html' %}
    
    

    block 块

    通过在母板中使用{% block  xxx %}来定义"块"。
    在子页面中通过定义母板中的block名来对应替换母板中相应的内容。
    
    #定义block
    {% block 块名 %}
    {% endblock  %} #还可以{{% endblock 块名 %}}来关闭标签,更加清新
    
    #使用block
    {% block 块名 %}
    
        #自己的内容   
    
    {% endblock  %}
    
    #母版内容和自己内容都使用
    {% block 块名 %}
    
        #自己的内容   
        {% block.super %}
    
    {% endblock  %}
    
    

    子页面替换母版 block块

    img
    img

    • 注意事项
    注意的点:
    
    1. {% extends 'base.html' %} 写在第一行   前面不要有内容 有内容会显示
    2. {% extends 'base.html' %}  'base.html' 加上引号   不然当做变量去查找
    3. 把要显示的内容写在block块中
    4. 定义多个block块,定义 css  js 块
    
    

    组件

    #作用
    可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
    
    #示列  单独建一个html  page
    <nav aria-label="Page navigation">
      <ul class="pagination">
        <li>
          <a href="#" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
        </li>
        {% for i in num %}
            <li><a href="#">{{ i }}</a></li>
        {% endfor %}
        <li>
          <a href="#" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
      </ul>
    </nav>
    
    #别的页面 引用
    {% include 'page.html' %}
    
    
  • 相关阅读:
    套件测试
    注解实战aftersuite和beforesuite
    注解实战Beforeclass和Afterclass
    Centos7下安装Mongodb
    java的算法实现冒泡
    注解实战BeforeMethed和afterMethed
    前端 HTML的规范
    前端 HTML标签介绍
    前端 HTML文档 详解
    前端 HTML 简介
  • 原文地址:https://www.cnblogs.com/TMesh/p/11832794.html
Copyright © 2020-2023  润新知