轻轻松松学Django(四):模板层(常用以及内置标签)

轻轻松松学Django(四):模板层

1.走近模板层

作为Web框架,Django需要一种便捷的方式来动态生成HTML。最常见的方法依赖模板。模板文件(templates)包含所需HTML输出的静态部分以及一些描述如何插入动态内容的特殊语法。有关使用模板创建HTML页面的动手示例,请继续阅读本博客。
Django定义了一个标准API,用于无论后台如何加载和渲染模板。加载包括查找给定标识符的模板并对其进行预处理,通常将其编译为内存中的表示形式。渲染意味着用上下文数据插入模板并返回结果字符串。
举个例子:
重写views.py 中的detail功能:

def detail(request, question_id):
    question = {'question_text': '你一般什么时候吃饭', 'choice': ['A:早上', 'B:晚上', 'C.中文']}
    return render(request, 'detail.html', {'question': question, 'question_id': question_id})

再在本项目的tempaltes文件中写一个detail.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>polls/index</title>
</head>
<body>
    <h3>{{ question.question_text }}</h3>
<ul>
{% for choice in question.choice %}
    <li>{{ choice }}</li>
{% endfor %}
</ul>
</body>
</html>

运行项目,浏览器输入http://127.0.0.1:8000/polls/6/
在这里插入图片描述
django默认的模板(html文件)都会存在templates文件夹中,注意可以将后端的数据传入到模板中,再渲染到前端中。注意后端的数据一定要通过字典的形式传入到模板文件之中,如果变量太多,可直接传入locals(),即传入后端所有的变量。

2. 模板层中常用标签

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

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

在第一部分的模板中我们就使用了for标签,实例可参考上面内容
补充:for … emptyfor 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。

{% for person in person_list %}
    <p>{{ person.name }}</p>
{% empty %}
    <p>sorry,no person here</p>
{% endfor %}
2.2 {{forloop}}

forloop.counter 表示的是循环的次数,而这个整数是从1开始计算的,所以当进行第一次循环的是时候forloop.counter的值是1
forloop.counter0 表示的是循环的次数,而这个整数是从0开始计算的,所以当进行第一次循环的是时候forloop.counter的值是0
forloop.revcounter 表示的是循环的次数,而这个整数是从末尾开始计算的,所以当进行最后一次循环的是时候的值是1
forloop.revcounter0 表示的是循环的次数,而这个整数是从末尾开始计算的,所以当进行最后一次循环的是时候的值是0
forloop.first 用于判断 如果为第一次循环 则返回TRUE
forloop.last 用于判断 如果为最后一次循环 则返回TRUE

2.3 if 标签

{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
对于此类表达式,了解对表达式求值时如何对运算符进行分组(即优先规则)非常重要。运算符的优先级从低到高依次为:
or,and,not,in,==,!=,<,>,<=,>=(这完全遵循Python)。

{% if num > 100 or num < 0 %}
    <p>成绩无效</p>
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}
    <p>不优秀</p>
{% endif %}
2.4 firstof

输出不为“ false”的第一个参数变量(即存在,不为空,不是错误的布尔值并且不是零数值)。如果所有传递的变量均为“ false”,则不输出任何内容。
用法示例:

{% firstof var1 var2 var3 %}

这等效于:

{% if var1 %}
    {{ var1 }}
{% elif var2 %}
    {{ var2 }}
{% elif var3 %}
    {{ var3 }}
{% endif %}

如果所有传递的变量均为False,您还可以使用文字字符串作为后备值:

{% firstof var1 var2 var3 "fallback value" %}
2.5 ifchanged

从循环的最后一次迭代检查值是否已更改。它有两种可能的用途。{% ifchanged %}

  1. 根据其先前状态检查其自己呈现的内容,并且仅在内容已更改时才显示。例如,这将显示天的列表,如果更改则仅显示月份:

{% for date in days %}
    {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
    <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
{% endfor %}
  1. 如果提供了一个或多个变量,请检查是否有任何变量已更改。例如,以下内容显示每次更改的日期,如果小时或日期已更改,则显示小时:
{% for date in days %}
    {% ifchanged date.date %} {{ date.date }} {% endifchanged %}
    {% ifchanged date.hour date.date %}
        {{ date.hour }}
    {% endifchanged %}
{% endfor %}

该ifchanged标签还可以使用一个可选如果值没有改变,这将显示子句:{% else %}

3.内置模板标签
3.1 autoescape

控制当前的自动转义行为。该标记采用on或 off作为参数,并确定自动转义在块内是否有效。该块用endautoescape结束标记关闭。
DTL模板中默认已经开启了自动转义,会将那些特殊字符串进行转义,比如会将< 转换为 &lt;> 转换为 &gt;’ (单引号)转换为 &#x27;" (双引号)转换为 "& 转换为 &amp
使用DTL的自动转义,可以使网站不容易出现XSS漏洞。
index函数
在这里插入图片描述
index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>polls/index</title>
</head>
<body>
    <p>autoescape on</p>
   {% autoescape on %}
      <p> {{ name }}</p>
       <p>{{ pwd }}</p>
       <p>{{ link }}</p>
   {% endautoescape %}
    <hr>
    <p>autoescape off</p>
   {% autoescape off %}
      <p> {{ name }}</p>
       <p>{{ pwd }}</p>
       <p>{{ link }}</p>
   {% endautoescape %}
</body>
</html>

在前端渲染后:
在这里插入图片描述

3.2 comment

主要作用就是用来注释,中间的内容不会渲染到前端。可以在第一个标签中插入可选注释。{% comment %}{% endcomment %}

<p>Rendered text with {{ pub_date|date:"c" }}</p>
{% comment "Optional note" %}
    <p>Commented out text with {{ create_date|date:"c" }}</p>
{% endcomment %}
3.3 block

模板继承:Django模板引擎中最强大(因此也是最复杂)的部分是模板继承。模板继承使您可以构建基本的“骨架”模板,该模板包含站点的所有常见元素,并定义子模板可以覆盖的块。
让我们从一个示例开始看一下模板继承,我们将下面这个模板称为base.html,定义了一个HTML骨架文档,您可以将其用于两栏页面。“子”模板的工作是用内容填充空白块。

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

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

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

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”。
同时,模板引擎将注意到其中的三个block标记,base.html会使用子模板的内容替换这些{% block block_name%}内容{% endblock %}块。根据上面的原理,最终html中实际内容如下:

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

<body>
    <div id="sidebar">
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">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块,因此将继承父模板中sidebar块的值。 父模板中标签内的内容始终用作后备。{% block %}

您可以根据需要使用任意多个继承级别。使用继承的一种常见方法是以下三级方法:

  • 创建一个base.html包含网站外观的通用模板
    base_SECTIONNAME.html为站点的每个“部分”

  • 创建一个模板。例如base_news.html,base_sports.html。这些模板全部扩展base.html并包括特定于部分的样式/设计。

  • 为每种类型的页面(例如新闻文章或博客条目)创建单独的模板。这些模板扩展了相应的节模板。

这种方法最大程度地提高了代码重用性,并有助于将项目添加到共享的内容

区域,例如部分范围的导航。

以下是使用继承的一些技巧

  • 如果在模板中使用,则{% extends %}必须是该模板中的第一个模板标记。否则模板继承将不起作用。
  • 更多的在你的基本模板标签是更好的。请记住,子模板不必定义所有父块,因此您可以在许多{% block %}中填写合理的默认值,然后仅在以后定义所需的块。。
  • 如果发现自己在多个模板中复制内容,则可能意味着您应该将该内容移至父模板中的。{% block %}

如果需要从父模板中获取块的内容,则可以使用变量来解决问题。如果要添加到父块的内容而不是完全覆盖它,这将很有用。使用插入的数据将不会自动转义,因为在父模板中已经转义了该数据(如有必要)。{{ block.super }}{{ block.super }}

3.4 extends

表示此模板扩展了父模板。
该标签可以两种方式使用:

  1. {% extends “base.html” %}(带引号)使用文字值 "base.html"作为要扩展的父模板的名称。
  2. {% extends variable%}使用的值variable。如果该变量的值为字符串,则Django将使用该字符串作为父模板的名称。如果变量求值为Template对象,则Django将使用该对象作为父模板。
    通常,模板名称是相对于模板加载器的根目录而言的。字符串参数也可以是以./或开头的相对路径…/。(./ 当前目录 )(…/ 父级目录)(/ 根目录例如)假定以下目录结构:
dir1/
    template.html
    base2.html
    my/
        base3.html
base1.htm

在中template.html,以下路径将有效:

{% extends "./base2.html" %}
{% extends "../base1.html" %}
{% extends "./my/base3.html" %}
3.5 csrf_token

跨站请求伪造保护:CSRF中间件和模板标签提供了易于使用的跨站点请求伪造保护 。当恶意网站包含链接,表单按钮或某些旨在使用您浏览器中访问恶意网站的登录用户的凭据在您的网站上执行某些操作的JavaScript时,就会发生这种类型的攻击。还涵盖了一种相关的攻击类型“登录CSRF”,攻击站点在其中诱骗用户的浏览器使用他人的凭据登录到该站点。
抵御CSRF攻击的第一道防线是确保GET请求 无副作用。然后可以按照以下步骤保护通过“不安全”方法(例如POST,PUT和DELETE)发出的请求。

要在您的视图中利用CSRF保护,请执行以下步骤:

  1. 默认情况下,该MIDDLEWARE设置(setting.py)中会激活CSRF中间件。如果您覆盖了该设置,请记住,
    'django.middleware.csrf.CsrfViewMiddleware’应该在假定已处理CSRF攻击的任何视图中间件之前进行设置。
  2. 如果不建议您禁用它,则可以csrf_protect()在要保护的特定视图上使用
    。在任何使用POST表单的模板中,如果表单用于内部URL,请csrf_token在元素中使用标记,例如:
    <form method="post">{% csrf_token %}
    
    对于以外部URL为目标的POST表单,不应执行此操作,因为这将导致CSRF令牌泄漏,从而导致漏洞。
  3. 在相应的视图函数中,确保 RequestContext使用来呈现响应,以使其正常工作。如果您使用的是函数,通用视图或contrib应用程序,那么这些内容都已使用,因此已经涵盖了。
    {% csrf_token%}render()RequestContext
3.6 url

返回与给定视图和可选参数匹配的绝对路径引用(不带域名的URL)。并将参数传入到莫版主之中

{% url 'some-url-name' arg1=v1 arg2=v2 %}

第一个参数是URL模式名称。它可以是带引号的文字或任何其他上下文变量。其他参数是可选的,并且应为以空格分隔的值,这些值将用作URL中的参数。上面的示例显示了传递位置参数(arg1 ,arg2为位置参数,'some-url-name’为url名称)。
例如,假设您有一个视图,app_views.client其URLconf带有一个客户端ID(此处client()是views文件中的方法 app_views.py)。URLconf行可能如下所示:

path('client/<int:id>/', app_views.client, name='app-views-client')

如果此应用程序的URLconf被包含在项目的URLconf中,例如以下路径:

path('clients/', include('project_name.app_name.urls'))

然后,您可以在模板中创建指向该视图的链接,如下所示

{% url 'app-views-client' client.id %}

template标签将输出字符串/clients/client/123/。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值