我叫補三補四,很高興見到大家,歡迎一起學習交流和進步
今天來講一講視圖
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 %}`標簽來加載你的自定義標簽或過濾器,然后在模板中使用它們。