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`这两个目录中查找模板文件。
3. 第二个字典配置:
• `'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 renderdef 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 templateregister = template.Library()@register.simple_tagdef 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 templateregister = 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 %}`标签来加载你的自定义标签或过滤器,然后在模板中使用它们。