django笔记-模板的使用以及is_safe详解

设计理念

  • 模板系统
    逻辑分离的解决方案
    我们将模板系统看作一个工具,用于控制表现方式和表示方式相关的逻辑。模板系统不应该支持超出这个基本目标的功能。

  • 避免冗余
    大多数动态网站会使用一些网站整体通用的设计——一个通用的页眉、页脚、导航栏,等等。Django 模板系统应该可以很容易地将这些元素存储在一个地方,从而减少重复的代码。

  • 从 HTML 中解耦
    模板系统不应该被设计成只能输出 HTML。它应该同样擅长生成其他基于文本的格式,或者仅仅是纯文本。

  • XML不应被用于模板语言
    使用 XML 引擎去解析模板会在编辑模板的过程中引入很多人为错误,并在模板处理中导致不可接受的开销。

  • 承担设计能力
    模板系统不应该有的设计是,使得模板可以在WYSIWYG(所见即所得)编辑器中也能显示得很好,比如 Dreamweaver。因为这是一个非常严重的限制,会让模板的语法不够好。Django 期望模板编写者有能力直接编辑 HTML 文本。

  • 更加直接的处理空格
    模板系统不应该用空白符来做神奇的事情。如果模板包含空白符,系统应该在处理文本时处理空格——只是显示它。任何不在模板标签中的空白符都应该显示出来。

  • 不要发明一种编程语言
    模板系统的目标不是发明一种编程语言。它的目标是提供足够的具有编程风格的功能,比如分支和循环,这对于做出表现相关的决策是至关重要的。:ref:`Django 模板语言(DTL)’ 旨在避免高级逻辑。

Django 模板系统认为模板通常是由设计师编写的,而不是程序员,因此不应该假设他了解 Python。

  • 安全与保障
    开箱即用的模板系统禁止包含恶意代码,例如删除数据库记录的代码。
    这就是模板系统不允许有任意Python代码的另一个原因。

  • 可扩展性
    模板系统应该认识到, 高阶的模板作者可能想扩展它.

这是自定义的模板标签和过滤器背后的理念.

MVT设计模型

作者是这样描述MVT模型的。
Django 似乎是一个 MVC 框架,但是您将控制器称为“视图”,并视图称为“模板”。 为什么不使用标准命名?
当然,标准化的名称是有争议的。
在我们对 MVC 的解释中,“视图”描述了呈现给用户的数据。数据看起来怎么样并不重要,重要的是哪些数据被呈现。该视图描述了您看到了哪些数据,而不是*您怎么看到数据。*这是一个微妙的区别。

所以,在我们的例子里,一个"视图(view)"是 Python 中针对一个特定 URL 的回调函数,此回调函数描述了需要展示的数据。

此外,将内容和展示效果分开是很明智的,展示效果就是模板。在 Django 里面,一个视图(view)描述了哪些数据会被展示,但是一个视图通常代表了一个模板,这个模板描述了数据是如何被展示的。

那控制器(Controller)在什么位置?在 Django 中,控制器可能指的是框架本身,框架会根据 Django 的 URL 配置,将请求分发到适当的视图(view)。

如果你想要首字母缩写, 你可能会说 Django 是一个 "MTV " 框架–即 "模型(Model) "、 “模板(Template)” 和 "视图(View). 这种划分更有意义。

当然, 在一天结束的时候, 它完成了工作。而且, 不管工作是怎样的, Django 以一种对我们来说最合乎逻辑的方式完成了。

模板渲染

from django.http import HttpResponse
from django.template import loader

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))

使用快捷函数

from django.shortcuts import render

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {'latest_question_list': latest_question_list}
    return render(request, 'polls/index.html', context)

语法与逻辑

  • {{ }} 变量语言
  • {% %} 流程控制语言

循环控制

{% for item in 列表 %}

#循环逻辑
{{forloop.counter}}表示当前是第几次循环,从1开始
{%empty%} 列表为空或不存在时执行此逻辑

{% endfor %}

判断逻辑

{% if ... %}
pass
{% elif ... %}
pass
{% else %}
pass
{% endif %}

注释

{# 单行注释 #}

{% comment %}
多行注释
{% endcomment %}

模板过滤器

自定义过滤器

在应用内创建名为templatetags的Python包,py模块名可自定,结构如下
在这里插入图片描述

# app_filter.py
from django.template import library

register = library.Library()

@register.filter(name="limit")
def limit(arg,length):
    # 超过length将被截断
    return arg[0:length]

在模板内的使用,需要先将自定义的模块加载进去{% load xx.py *}

{% load app_filter %}
{{ title }}
<a href="{% url 'first:detail' %}">{{ title }}</a>
<p>{{ arg | limit:2}}</p>

is_safe参数

官方文档说明

  • 原始字符串是本机Python字符串。在输出时,如果自动转义生效并且保持不变,它们将被转义,否则。

  • 安全字符串是在输出时被标记为安全进一步转义的字符串。任何必要的逃脱已经完成。它们通常用于包含原始HTML的输出,该HTML旨在在客户端进行解释。

  • 原因is_safe是必要的,因为有很多正常的字符串操作会将一个SafeData对象变回一个普通的str对象,而不是试图全部捕获它们,这将非常困难,Django会在过滤器完成后修复损坏。

  • 过滤器默认情况下 is_safe为False
    刚接触的小伙伴通过看官方文档可能看不明白is_safe参数的作用,一句话,该参数决定经过过滤器后返回的字符串是否会被html解释转义,决定其是否被转义的条件是返回值是否是SafeText类型

  • 通过一个例子来说明

# index.html
<a href="{% url 'first:detail' %}">{{ title }}</a>
<p>{{ arg | limit:2}}</p>
<p>{{ "<h1>test</h1>" | safe_f }}</p>
  • 此时,is_safe为True,只要返回值arg经过过滤器处理后不失去html结构(闭合标签的前半部分被破坏如<h1>被改成<h1),该字符串到前端就会被html转义。
# app_filter.py
@register.filter(is_safe=True,name="safe_f")
def safe_f(arg):
	# print(isinstance(arg, SafeText)) ==> True
    arg = arg.replace("test","hahahahah")
    # print(isinstance(arg, SafeText)) == > False
    return arg
  • 当is_safe被设置为False,如果在过滤器内部只是简单的一些判断,没有修改字符串,那么返回值仍然是SafeText,仍然会被转义。但是当字符串发生改变时,即使是有html结构的字符串,仍然不会被转义
# app_filter.py
@register.filter(is_safe=True,name="safe_f")
def safe_f(arg):
	# print(isinstance(arg, SafeText)) ==> True
    arg = arg.replace("test","hahahahah")# 如果将此行注释,那么该标签会被转义
    # print(isinstance(arg, SafeText)) == > False
    return arg

在这里插入图片描述
在这里插入图片描述
当is_safe=False时,如果返回的数据类型不是SafeText类型,将不会被转义

expects_localtime时区

@register.filter(expects_localtime=True)
def businesshours(value):
    try:
        return 9 <= value.hour < 17
    except AttributeError:
        return ''

  • 设置此标志后,如果过滤器的第一个参数是时区感知日期时间,则根据模板中时区转换规则,Django会在适当时将其转换为过滤器之前将其转换为当前时区。
    

不要在模板内使用硬编码

在模板内使用硬编码将导致维护起来很麻烦,所谓硬编码就是直接将链接写在模板内,如

<li><a href="/first/detail/">{{ content }}</a></li>

根据视图路由的命名空间来形成反向引用

<a href="{% url 'first:detail' %}">{{ title }}</a>

此时,herf将指向first应用对应的name为detail视图函数。
在路由中应如下:

# 子应用路由
urlpatterns = [
    url(r'^index/$',views.index,name="index"),
    url(r'^detail/$',views.detail,name="detail"),
]
# 项目根路由
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^first/',include(first.urls,namespace="first",app_name="first"))
]

传入app_name时,namespace必须要传入,否则将抛出异常
在这里插入图片描述

模板继承

# 父模板
{% block 名称 %}
default html
{% endblock  名称 %}
# 子模板 标签extends:继承,写在子模板文件的第一行。

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

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

参考:官方文档

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值