Django与模板

我叫补三补四,很高兴见到大家,欢迎一起学习交流和进步

今天来讲一讲视图

Django与模板文件 工作流程

模板引擎:主要参与模板渲染的系统。

内容源:输入的数据流。比较常见的有数据库、XML文件和用户请求这样的网络数据。

模板:一般是和语言相关的文本。

工作流程:

作为一个web框架,Django自带了一套模板系统动态生成HTML文本

模板主要包含两个部分:HTML的静态部分和描述如何插入动态内容的特殊语法

模板系统的相关配置

模板的配置也在settings.py当中实现

复制代码
  TEMPLATES = [  # 模板配置变量

    {

        'BACKEND': 'django.template.backends.django.DjangoTemplates',  # 配置使用自带模板

        'DIRS': [  # 配置寻址目录

            '/var/www/html/site.com',

            '/var/www/html/default',

        ]

    },

    {

        'BACKEND': 'django.template.backends.jinja2.Jinja2',  # 配置使用Jinja2模板

        'DIRS': '/var/www/html/another_app'  # 配置寻址路径

    }

]

这段代码是Django框架中用于配置模板引擎的设置。Django是一个高级的Python Web框架,它允许开发者使用Python编写服务器端代码。模板引擎是Django中用于生成HTML页面的工具,它允许开发者将动态内容插入到静态HTML模板中。

代码中的`TEMPLATES`变量是一个列表,包含多个字典,每个字典定义了一组模板配置。这些配置告诉Django如何渲染模板。

下面是代码的详细解释:

  1. `TEMPLATES = [ ... ]`:定义了一个名为`TEMPLATES`的列表,其中包含多个模板配置。

  2. 第一个字典配置:

• `'BACKEND': 'django.template.backends.django.DjangoTemplates'`:指定使用Django自带的模板引擎。这是Django默认的模板引擎,它基于Python编写。

• `'DIRS': [ ... ]`:定义了一个目录列表,Django会在这些目录中查找模板文件。在这个例子中,Django会在`/var/www/html/site.com`和`/var/www/html/default`这两个目录中查找模板文件。

  1. 第二个字典配置:

• `'BACKEND': 'django.template.backends.jinja2.Jinja2'`:指定使用Jinja2模板引擎。Jinja2是一个流行的Python模板引擎,它支持更复杂的模板语法和功能。

• `'DIRS': '/var/www/html/another_app'`:定义了一个单一的目录,Django会在该目录中查找Jinja2模板文件。在这个例子中,Django会在`/var/www/html/another_app`目录中查找模板文件。

通过这种配置,Django项目可以同时使用Django自带的模板引擎和Jinja2模板引擎,从而提供更大的灵活性和选择。开发者可以根据需要选择使用哪种模板引擎,或者在不同的应用中使用不同的模板引擎。

(简单理解BACKEND就是import了一些库)

模板语言

模板引擎可以识别模板中的特殊结构,以动态生成文本。主要的特殊结构有变量和标签。

在进行渲染的时候,模板引擎根据上下文对模板中的变量进行替换,并且根据操作标签来执行操作,输出文本。

Django的模板语言当中包含了四种结构:变量、标签、过滤器和注释

Django模板语言包含四个主要结构:变量、标签、过滤器和注释。

1.变量(Variables)

变量用于在模板中显示来自视图(view)传递的数据。变量通常以双大括号`{{ }}`包裹。例如:

复制代码
<p>Hello, {{ name }}!</p>

如果`name`的值是`"Alice"`,那么模板渲染后会显示:

复制代码
<p>Hello, Alice!</p>

2.标签(Tags)

标签用于控制模板的逻辑,例如循环、条件判断、加载外部模板等。标签以`{% %}`包裹。常见的标签包括:

• `{% if %}`:条件判断

• `{% for %}`:循环

• `{% include %}`:加载外部模板

• `{% extends %}`和`{% block %}`:模板继承

例如:

复制代码
{% if user.is_authenticated %}

    <p>Welcome, {{ user.username }}!</p>

{% else %}

    <p>Please login.</p>

{% endif %}

3.过滤器(Filters)

过滤器用于对变量进行格式化或转换。过滤器通过管道符号`|`应用到变量上。例如:

复制代码
<p>{{ date|date:"Y-m-d" }}</p>

如果`date`是一个`datetime`对象,过滤器会将其格式化为指定的格式。

Django内置了许多过滤器,如`upper`、`lower`、`truncatewords`等。

4.注释(Comments)

模板注释用于在模板中添加说明性内容,这些内容在渲染时会被忽略。Django模板注释使用`{# #}`包裹。例如:

复制代码
{# This is a comment in the template #}

<p>Hello, {{ name }}!</p>

模板继承

在真实开发环境下,不乏不同网页结构和样式一样的情况,为减少重复,增加可维护性,我们会使用模板继承

具体实现:

在Web开发中,模板继承是一种常见的模式,它允许你创建一个基础模板,然后让其他模板继承这个基础模板的结构,同时能够覆盖或添加特定的内容。这种机制在许多模板引擎中都有实现,比如Django(Python)、Jinja2(Python)、Twig(PHP)等。

实现步骤

1.创建基础模板(base.html)

基础模板定义了页面的通用结构,包括HTML的基本骨架、头部、尾部、导航栏等。你可以在基础模板中定义一些"块"(block),这些块可以在子模板中被覆盖。

复制代码
<!-- base.html -->

<!DOCTYPE html>

<html lang="en">

<head>

    <link rel="stylesheet" href="style.css">

    {% block title %}<title>Default Title</title>{% endblock %}

</head>

<body>

    <div id="sidebar">

        <ul>

            <li>主页</li>

            <li>帮助</li>

        </ul>

    </div>

    <div id="content">

        {% block content %}

        <!-- 默认内容 -->

        {% endblock %}

    </div>

    <footer id="footer">我是页脚</footer>

</body>

</html>

2.创建子模板并继承基础模板

子模板通过使用`{% extends %}`标签来继承基础模板。然后,子模板可以使用`{% block %}`标签来覆盖基础模板中定义的块。

复制代码
<!-- home.html -->

{% extends "base.html" %}



{% block title %}<title>主页</title>{% endblock %}



{% block content %}

    <h1>欢迎来到主页!</h1>

    <p>虽然这个网站什么内容都没有,但是它展示了使用模板继承的用法。</p>

{% endblock %}

3.Django视图函数中指定模板

在你的Django视图函数中,你需要指定使用哪个模板来渲染页面。

复制代码
from django.shortcuts import render



def home(request):

    return render(request, 'home.html')

4.模板引擎如何处理继承

当Django的模板引擎处理`home.html`时,它会首先加载`base.html`,然后查找`home.html`中定义的块,并用这些块替换`base.html`中的相应块。最终,模板引擎会生成一个完整的HTML页面,其中包含了基础模板的结构和子模板的特定内容。

在上面代码中,实现继承的关键是extends标签。它告诉模板引擎该模板扩展了另外一个模板。当模板系统渲染主页面时,首先要找到父模板,即base.html文件。在父模板中,引擎会找到两个block标签,然后用子模板中的内容填充这个区域。

多级继承

常见的网站模板继承结构往往是三级的,通常用于提高代码复用性和维护效率。


1.第一级模板(基础模板)

第一级模板是整个网站的"骨架",它定义了网站的整体布局和通用元素。这些元素通常包括:

• 头部(Header):包含网站的logo、导航栏(Navigation Bar)、登录/注册入口等。

• 底部(Footer):包含版权信息、联系方式、网站地图、隐私政策等。

• 侧边栏(Sidebar,可选):用于放置广告、快捷链接或其他辅助信息。

• 主内容区域(Main Content Area):这是页面的核心区域,用于展示具体的内容。第一级模板通常会在这里预留一个占位符(Placeholder),供子模板填充具体内容。

第一级模板的作用是为整个网站提供一个统一的外观和风格,确保所有页面在结构和视觉上保持一致。例如,一个电商网站的头部可能始终显示"首页""商品分类""购物车""我的订单"等导航链接,而底部则包含"关于我们""售后服务""联系方式"等通用信息。


2.第二级模板(功能分类模板)

第二级模板是对第一级模板的扩展,它专注于网站的某个功能模块或分类。例如:

• 用户中心:包含用户相关的功能,如"我的订单""我的收藏""个人信息""账户设置"等。

• 商品中心:包含商品相关的功能,如"商品分类""商品列表""热门商品推荐""搜索结果"等。

• 帮助中心:包含常见问题解答(FAQ)、联系客服、使用说明等。

第二级模板会继承第一级模板的结构,并在主内容区域填充与该功能模块相关的通用内容。例如,在"用户中心"模板中,主内容区域可能会显示一个用户操作的导航菜单,如:

• 我的订单:显示订单列表。

• 我的收藏:显示收藏的商品列表。

• 个人信息:提供用户信息的编辑表单。

这些内容通常以列表的形式呈现,为第三级模板提供进一步的细化空间。第二级模板的作用是将网站的功能模块化,方便管理和扩展。


3.第三级模板(具体页面模板)

第三级模板是具体页面的实现,它继承第二级模板,并在主内容区域填充具体的页面内容。例如:

• 用户详情页面:继承"用户中心"模板,展示用户的详细信息,如头像、昵称、注册时间、积分等。

• 商品详情页面:继承"商品中心"模板,展示商品的详细信息,如商品图片、价格、规格、用户评价、购买按钮等。

• 帮助页面:继承"帮助中心"模板,展示具体的帮助内容,如常见问题的详细解答、联系方式等。

第三级模板的作用是实现具体的功能页面,满足用户的具体需求。它通过继承第二级模板,复用了通用的布局和功能模块,同时通过填充具体的内容,实现了页面的个性化。


4.模板继承的实现(以HTML为例)

模板继承可以通过模板引擎(如Django模板、Jinja2等)实现。以下是一个简单的示例:

第一级模板(base.html)

复制代码
<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>{% block title %}My Website{% endblock %}</title>

</head>

<body>

    <header>

        <h1>My Website</h1>

        <nav>

            <ul>

                <li>Home</li>

                <li>User Center</li>

                <li>Product Center</li>

                <li>Help</li>

            </ul>

        </nav>

    </header>



    <main>

        {% block content %}

        <!-- 主内容区域的占位符 -->

        {% endblock %}

    </main>



    <footer>

        <p>© 2025 My Website</p>

    </footer>

</body>

</html>

第二级模板(user_center.html)

复制代码
{% extends "base.html" %}

{% block title %}User Center - My Website{% endblock %}

{% block content %}

    <h2>User Center</h2>

    <ul>

        <li>My Orders</li>

        <li>My Favorites</li>

        <li>Profile</li>

    </ul>

    <div>

        {% block user_content %}

        <!-- 用户中心的具体内容占位符 -->

        {% endblock %}

    </div>

{% endblock %}

第三级模板(user_profile.html)

复制代码
{% extends "user_center.html" %}



{% block title %}Profile - User Center - My Website{% endblock %}



{% block user_content %}

    <h3>User Profile</h3>

    <p>Welcome, {{ user.name }}!</p>

    <p>Email: {{ user.email }}</p>

    <p>Registered since: {{ user.register_date }}</p>

{% endblock %}

帮助页面的实现

帮助页面的实现可以类似地继承"帮助中心"模板。例如:

• 帮助中心模板(help_center.html)

复制代码
{% extends "base.html" %}



{% block title %}Help Center - My Website{% endblock %}



{% block content %}

    <h2>Help Center</h2>

    <ul>

        <li>FAQ</li>

        <li>Contact Us</li>

    </ul>

    <div>

        {% block help_content %}

        <!-- 帮助中心的具体内容占位符 -->

        {% endblock %}

    </div>

{% endblock %}

• 具体帮助页面(help_faq.html)

复制代码
{% extends "help_center.html" %}



{% block title %}FAQ - Help Center - My Website{% endblock %}



{% block help_content %}

    <h3>Frequently Asked Questions</h3>

    <p>Here are some common questions and answers...</p>

    <!-- 具体的FAQ内容 -->

{% endblock %}

5.总结

这种三级模板继承结构的优点包括:

• 代码复用性高:通过继承,通用的布局和功能可以在多个页面中复用。

• 维护方便:只需要修改基础模板或功能分类模板,即可更新整个网站的外观或功能模块。

• 扩展性强:可以轻松添加新的功能模块或页面,而无需重新设计整个布局。

这种结构在实际开发中非常常见,尤其是在大型网站或复杂的应用中,能够显著提高开发效率和代码质量。

字符转义

用处

在HTML模板渲染中,如果直接将用户输入的内容(如用户名)插入到HTML中,而没有进行适当的转义或过滤,就可能引发XSS(跨站脚本)攻击。XSS攻击是一种安全漏洞,攻击者通过在用户输入中嵌入恶意代码(如JavaScript脚本),当这些代码被渲染到页面上时,就会在用户的浏览器中执行,从而可能窃取用户信息、篡改页面内容或进行其他恶意操作。

例如:

你好, {{ username }}

如果用户将用户名设置为 <script>alert('一次攻击')</script> ,那么渲染后的HTML就会变成:

你好, <script>alert('一次攻击')</script>

当页面加载时,浏览器会执行这段JavaScript代码,这种攻击方式称之为XSS攻击:

XSS攻击的核心就是攻击者通过某种方式(通常是用户输入)将恶意脚本注入到网页中,然后让这个脚本在其他用户的浏览器中执行。简单来说,就是:

攻击者→输入恶意脚本→网站响应体返回脚本→浏览器执行脚本

我们可以用一个更详细的流程来解释这个过程:


1.正常流程

正常情况下,用户输入的内容是安全的,网站会正确处理并显示这些内容。例如:

• 用户输入:`小明`

• 网站处理后显示:`你好,小明`


2.XSS攻击的流程

XSS攻击的关键在于攻击者利用了网站对用户输入的处理漏洞,将恶意脚本注入到网页中。具体步骤如下:

步骤1:攻击者输入恶意脚本

攻击者在网站的输入框中输入的不是正常内容,而是一段JavaScript代码。例如:

复制代码
<script>alert('你被攻击了!')</script>

步骤2:网站将恶意脚本返回到响应体中

如果网站没有对用户输入进行过滤或转义,就会直接将这段恶意代码插入到网页中。例如,网站的欢迎页面会变成:

复制代码
<p>你好,<script>alert('你被攻击了!')</script></p>

步骤3:浏览器执行恶意脚本

当其他用户访问这个页面时,浏览器会将这段HTML代码解析并渲染到页面上。由于`<script>`标签内的内容是可执行的JavaScript代码,浏览器会自动执行这段代码,从而弹出一个警告框,显示"你被攻击了!"


3.关键点:请求体和响应体

• 请求体(Request Body):攻击者通过输入框或其他方式将恶意脚本发送给服务器。这是攻击的"入口"。

• 响应体(Response Body):服务器将用户输入的内容(包括恶意脚本)返回到网页中。这是攻击的"出口"。

XSS攻击的核心就是攻击者通过请求体注入恶意脚本,然后让服务器将这些脚本嵌入到响应体中,最终在其他用户的浏览器中执行。


4.XSS攻击的类型

XSS攻击主要有两种类型:

存储型XSS(Stored XSS)

• 特点:恶意脚本被存储在服务器上(如数据库中),每次其他用户访问页面时,都会触发脚本执行。

• 例子:攻击者在论坛发帖时插入恶意脚本,其他用户查看帖子时就会被攻击。

反射型XSS(Reflected XSS)

• 特点:恶意脚本直接通过URL或表单提交到服务器,服务器将脚本反射回页面,用户访问时触发脚本执行。

• 例子:攻击者构造一个带有恶意脚本的链接,用户点击后,脚本会被服务器反射到页面并执行。

Django转义处理

使用Django处理这种问题有两种选择。

(1)对不信任的变量执行escape过滤,这个过滤器会对潜在的危险字符串进行转义。这个方法依赖开发者调用的转义过滤器。鉴于开发者有可能会忘记调用这个过滤器,因此网页有可能还是会被攻击。

(2)使用Django自动对HTML文本进行转义。默认情况下,Django会对模板中变量的输出进行自动转义,这是一个比较理想的处理方式。

具体地说,5个字符串会被自动转义,它们分别如下:"<"变为"<"">"变为">",单引号变为"'",双引号变为""""&"变为"&"。

Django几乎为所有的行为都提供配置,转义自然也不例外。有时候模板变量包含开发者打算作为原始HTML呈现的数据,那么这时可能希望内容不被转义。

要想对单个变量关闭自动转义功能,则可以使用safe过滤器,如下面的模板代码:

这个会转义: {{ data }} 这个不会转义: {{ data|safe }}

另外,也可以控制对模板的自动转义,这时要用到autoescape标签,这个标签用来将要控制的模板包裹起来,例如:

复制代码
{% autoescape off %}

这个不会被自动转义{{ data }}.

{% autoescape on %}

重新开启自动转义 {{ name }}

{% endautoescape %}

这个也不会被自动转义 {{ other_data }}

{% endautoescape %}

需要注意的是,过滤器是支持字符串作为参数的。这些字符串并不会被自动转义,这背后的思想是模板的作者应该控制文本的内容。因此,开发者应该确保在编写模板时对文本进行正确的转义。

自定义标签和过滤器

自定义标签

自定义标签和和过滤器应该统一放在放在一个文件当中------为此,可以在应用到目录当中创建一个templatetags文件夹:

myapp/

├── init.py

├── models.py

├── templatetags/

│ ├── init.py

│ └── customize.py

├── tests.py

└── views.py

并且将模块放在customize.py当中

完整流程如下:

1. 创建自定义标签库:

• 在你的Django应用目录下(例如`myapp`),创建一个名为`templatetags`的文件夹。

• 在`templatetags`文件夹内,创建一个空的`init.py`文件,使其成为一个Python包。

• 在`templatetags`文件夹内,创建一个新的Python文件,比如`customize.py`,这将包含你的自定义标签和过滤器。

2. 编写自定义标签:

• 在`customize.py`文件中,你可以定义自定义标签和过滤器。例如,创建一个简单的标签:

复制代码
from django import template



register = template.Library()



@register.simple_tag

def hello_name(name):

    return f"Hello, {name}!"

3. 加载自定义标签:

• 在你的Django模板文件中,使用`{% load %}`标签来加载你的自定义标签库。假设你的自定义标签库位于`myapp/templatetags/`目录下,你可以这样加载它:

复制代码
{% load customize %}

4. 使用自定义标签:

• 加载标签库后,你可以在模板中使用你定义的标签。例如,使用上面定义的`hello_name`标签:

复制代码
<p>{% hello_name "Alice" %}</p>

这将在模板中输出:`<p>Hello, Alice!</p>`

在Django中编写自定义过滤器与编写自定义标签类似,但过滤器用于处理模板变量的值。以下是编写自定义过滤器的步骤:

自定义过滤器

1. 创建自定义 过滤器 库:

• 确保你的Django应用目录下有一个`templatetags`文件夹,并且在该文件夹内有一个`init.py`文件。

2. 编写自定义过滤器:

• 在`templatetags`文件夹内,创建一个新的Python文件,比如`customize.py`,这将包含你的自定义过滤器。

3. 定义过滤器:

• 在`customize.py`文件中,你可以定义一个或多个过滤器。每个过滤器都是一个函数,它接收一个值并返回处理后的值。例如:

复制代码
from django import template



register = template.Library()



@register.filter(name='upper')

def upper(value):

    return value.upper()



@register.filter(name='lower')

def lower(value):

    return value.lower()

在这个例子中,我们定义了两个过滤器:`upper`和`lower`。`upper`过滤器将输入的字符串转换为大写,而`lower`过滤器将输入的字符串转换为小写。

4. 加载自定义过滤器:

• 在你的Django模板文件中,使用`{% load %}`标签来加载你的自定义过滤器库。例如:

复制代码
{% load customize %}

5. 使用自定义过滤器:

• 加载过滤器库后,你可以在模板中使用你定义的过滤器。例如,使用上面定义的`upper`和`lower`过滤器:

复制代码
<p>{{ my_string|upper }}</p>

<p>{{ my_string|lower }}</p>

这将在模板中输出:

复制代码
<p>MY_STRING</p>

<p>my_string</p>

两者比较

它们都是在`templatetags`目录下创建的,都需要使用`template.Library()`来注册,并且都需要在模板中使用`{% load %}`标签来加载。不过,它们的用途和工作方式有所不同:

自定义标签(Tags)

• 用途:自定义标签通常用于执行一些操作,比如条件判断、循环等,它们可以包含一些逻辑处理。

• 工作方式:标签通常不返回值,而是执行某些操作,比如输出HTML代码、调用函数等。

• 示例:一个自定义标签可能用于显示一个用户列表,或者根据某些条件来决定是否显示某些内容。

自定义过滤器(Filters)

• 用途:过滤器主要用于修改变量的值,比如格式化字符串、转换数据类型等。

• 工作方式:过滤器接收一个值作为输入,处理这个值,然后返回处理后的结果。

• 示例:一个自定义过滤器可能用于将字符串转换为大写或小写,或者用于格式化日期。

创建和注册过程

无论是标签还是过滤器,它们的创建和注册过程都非常相似:

  1. 创建`templatetags`目录:在你的应用目录下创建一个名为`templatetags`的目录,并在其中创建一个Python文件(如`customize.py`)。

  2. 导入`template`模块:在Python文件中导入Django的`template`模块。

  3. 创建`Library`实例:创建一个`template.Library()`的实例,并给它一个别名(通常是`register`)。

  4. 注册标签或过滤器:使用`@register.tag`装饰器来注册标签,使用`@register.filter`装饰器来注册过滤器。

  5. 定义标签或过滤器:定义标签或过滤器的函数,这些函数将包含标签或过滤器的逻辑。

  6. 在模板中加载和使用:在模板文件中使用`{% load %}`标签来加载你的自定义标签或过滤器,然后在模板中使用它们。

相关推荐
百结2142 小时前
Mysql数据库操作
数据库·mysql·oracle
keep one's resolveY3 小时前
时区问题解决
数据库
Leinwin3 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
qq_417695053 小时前
机器学习与人工智能
jvm·数据库·python
漫随流水3 小时前
旅游推荐系统(view.py)
前端·数据库·python·旅游
ego.iblacat3 小时前
MySQL 服务基础
数据库·mysql
yy我不解释4 小时前
关于comfyui的mmaudio音频生成插件时时间不一致问题(一)
python·ai作画·音视频·comfyui
Maverick065 小时前
Oracle Redo 日志操作手册
数据库·oracle
紫丁香5 小时前
AutoGen详解一
后端·python·flask
FreakStudio5 小时前
不用费劲编译ulab了!纯Mpy矩阵micronumpy库,单片机直接跑
python·嵌入式·边缘计算·电子diy