lask 中的 Jinja2 是什么
jinja2 是 Flask 作者開發的一個模板系統,起初是仿 Django 模板的一個模板引擎,為 Flask 提供模板支持,由于其靈活,快速和安全等優點被廣泛使用。當我們開發 Web 應用程序時,通常需要將數據動態地渲染到 HTML 模板中,而 Python jinja2 模版技術正是為此而生的。
要了解jinja2,那么需要先理解模板的概念。模板在 Python 的web開發中廣泛使用,它能夠有效的將業務邏輯和頁面邏輯分開,使代碼可讀性增強、并且更加容易理解和維護。
模板簡單來說就是一個其中包含 占位變量 表示 動態 部分的文件,模板文件在經過動態賦值后,返回給用戶。
模板渲染流程
Jinja2 是一個流行的 Python 模板引擎,它可以幫助我們將數據渲染到各種格式的文檔中,如 HTML、XML、Markdown 等。Jinja2 具有以下幾個特性:
使用 pip 命令可以很容易地安裝 Jinja2:
pip install Jinja2
Jinja2 的基本語法與 Python 很相似,包括變量、表達式、控制結構等。下面是一些示例:
<!-- 變量 -->
<p>Hello, {{ name }}!</p>
<!-- 表達式 -->
{% if count > 10 %}
<p>There are too many items.</p>
{% else %}
<p>There are {{ count }} items.</p>
{% endif %}
<!-- 循環 -->
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
在這個示例中,我們使用了變量、表達式和循環結構來渲染模板。變量使用 {{ ... }} 語法,表達式使用 {% ... %} 語法,循環結構使用 {% for ... in ... %} ... {% endfor %} 語法。
Jinja2中最強大的部分就是模板繼承。模板繼承允許我們創建一個基本(骨架/Base)文件,其他模版文件從該骨架文件繼承,然后針對需要的地方進行修改。
Jinja2的Base文件中,利用 block 關鍵字表示其包含的內容可以進行修改。可以幫助我們避免重復的代碼和布局。
下面是一個示例:
<!-- base.html -->
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
<!-- page.html -->
{% extends "base.html" %}
{% block title %}My Page{% endblock %}
{% block content %}
<h1>Welcome to my page!</h1>
{% endblock %}
在這個示例中,我們定義了一個基礎模板 base.html,它包含了頁面的基本結構和布局。我們還定義了一個子模板 page.html,它繼承了 base.html,并覆蓋了其中的標題和內容塊。
除了模板繼承之外,Jinja2 還支持模板包含,可以將重復的代碼抽象為一個單獨的模板,然后在其他模板中引用它。
這可以幫助我們避免重復的代碼和布局。下面是一個示例:
<!-- header.html -->
<header>
<h1>My Website</h1>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</header>
<!-- page.html -->
{% include "header.html" %}
<main>
<h1>Welcome to my page!</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</main>
{% include "footer.html" %}
在這個示例中,我們定義了一個頭部模板 header.html,它包含了網站的標題和導航菜單。然后我們在頁面模板 page.html 中引用了頭部模板和尾部模板 footer.html,以構建完整的頁面。
使用模板包含可以幫助我們更好地組織代碼和布局,使代碼更易于維護和擴展。
變量可以通過 過濾器 進行修改,過濾器可以理解為是jinja2里面的內置函數和字符串處理函數。
常用的過濾器有:
過濾器名稱 | 說明 |
safe | 渲染時值不轉義 |
capitialize | 把值的首字母轉換成大寫,其他子母轉換為小寫 |
lower | 把值轉換成小寫形式 |
upper | 把值轉換成大寫形式 |
title | 把值中每個單詞的首字母都轉換成大寫 |
trim | 把值的首尾空格去掉 |
striptags | 渲染之前把值中所有的HTML標簽都刪掉 |
join | 拼接多個值為字符串 |
replace | 替換字符串的值 |
round | 默認對數字進行四舍五入,也可以用參數進行控制 |
int | 把值轉換成整型 |
除了上述特性,Jinja2 還有其他一些有用的功能,下面介紹其中幾個:
在模板中渲染用戶提供的數據時,安全性是一個非常重要的問題。Jinja2 提供了一個安全過濾器,可以幫助我們過濾掉一些危險的 HTML 標簽和屬性,以防止 XSS 攻擊等安全問題。
安全過濾器示例:
{{ user_input|safe }}
除了基本的循環結構之外,Jinja2 還提供了一些高級的循環控制結構,比如 break、continue 和 loop.index0 等。這些控制結構可以幫助我們更好地控制循環過程。
在for循環中,jinja2提供了一些特殊的變量,用以來獲取當前的遍歷狀態:
變量 | 描述 |
loop.index | 當前迭代的索引(從1開始) |
loop.index0 | 當前迭代的索引(從0開始) |
loop.first | 是否是第一次迭代,返回bool |
loop.last | 是否是最后一次迭代,返回bool |
loop.length | 序列中的項目數量 |
loop.revindex | 到循環結束的次數(從1開始) |
loop.revindex0 | 到循環結束的次數(從0開始) |
循環控制結構示例:
{% for item in items %}
{% if item=='stop' %}
{% break %}
{% elif item=='skip' %}
{% continue %}
{% endif %}
<li>{{ loop.index0 }}: {{ item }}</li>
{% endfor %}
除了在模板中定義變量之外,Jinja2 還支持在 Python 代碼中定義全局變量,然后在模板中使用。這可以幫助我們更好地組織代碼和數據。
自定義全局變量示例:
from jinja2 import Environment
# 定義全局變量
my_var='Hello, world!'
# 創建模板引擎
env=Environment()
# 添加全局變量
env.globals['my_var']=my_var
# 渲染模板
template=env.from_string('<p>{{ my_var }}</p>')
result=template.render()
print(result)
在這個示例中,我們定義了一個全局變量 my_var,然后將它添加到模板引擎的全局變量中。最后,我們使用模板引擎渲染了一個模板,并輸出了結果。
jinja2模塊中有一個名為Enviroment的類,這個類的實例用于存儲配置和全局對象,然后從文件系統或其他位置中加載模板。
大多數應用都在初始化的時候創建一個Environment對象,并用它加載模板。Environment支持兩種加載方式:
參數:
使用包加載器來加載文檔的最簡單的方式如下:
from jinja2 import PackageLoader,Environment
# 創建一個包加載器對象
env=Environment(loader=PackageLoader('項目xx包目錄','templates'))
# 獲取一個模板文件
template=env.get_template('bast.html')
# 渲染
template.render(name='daxin',age=18)
文件系統加載器,不需要模板文件存在某個Python包下,可以直接訪問系統中的文件
Jinja2 是一個強大而靈活的 Python 模板引擎,它可以幫助我們將數據渲染到各種格式的文檔中。它具有簡單而靈活的語法、支持模板繼承和包含、支持過濾器和控制結構等特性。如果你需要在 Python 中使用模板引擎,Jinja2 是一個不錯的選擇。
當然,除了可以在 Python Web 開發過程中使用Jinja2模版,如果大家在做自動化腳本(自動化用例)時也可以使用它,可以根據相關自動化信息(比如:用例編號、步驟、斷言等)批量生成不同自動化測試用例(腳本)。總之,Jinja2 的使用場景可以用于多種需求下,今天的文章就介紹到這里了,感謝大家的閱讀。
擊右上方紅色按鈕關注“小鄭搞碼事”,每天都能學到知識,搞懂一個問題!
還是那句話,前端頁面渲染就四種方式。只要愿意學,花點時間從理論到實踐搞一遍,很容易就學會了。往后工作中天天用,進一步深入研究。
四種方式如下圖所示:
前兩篇我以將后端模板渲染和客戶端渲染兩種渲染方式的實現思路和優缺點都說過了。
今天來聊一下第三種渲染方式—node中間層。都是很好理解很容易搞懂的玩意,沒接觸過的同學,不要想太復雜。
上一篇我講的客戶端渲染,相對于上上篇講的后端模板渲染來說,它的優點是前后端分離開發,后臺只負責提供數據,前端能夠盡量發揮自己端的構建生態優勢。而缺點是由于首屏數據需要等到JS加載完成才能顯示,服務端返回的是空DOM結構,所以首屏等待時間長,體驗不好。
那么今天我要說的第三種頁面渲染方式,即能夠保留前后端分離開發的優勢,又能夠實現首屏數據的快速響應。
通過一張圖來看一下整體思路。
為了大家更好的理解,下面,我對著這張圖將整個過程也解釋一遍。
1. 前端發出一個請求URL
2. node層接收到這個請求,然后根據請求信息,向后端服務器發起請求,獲取數據
3. 后端服務器接收到請求,然后根據請求信息,從數據庫或者其他地方獲取相應的數據,返回給node層
4. node層根據這些數據渲染好首屏HTML
5. node層將HTML文本返回給前端
傳統的B/S架構是:瀏覽器-后端服務器-瀏覽器
加入node層的架構是:瀏覽器-node-后端服務器-node-瀏覽器
其中node層也是由前端開發來掌控的。所以后端依然只負責向前端提供數據。
由此可見,這種方式的優點就是:
第一. 保留了后端模板渲染(node層實現),首屏快速響應,SEO友好
第二. 保留前后端分離開發模式
同時,不足的地方是:
第一. 多了一個中間層,應用的性能有所降低
第二. 增加了架構的復雜度,不穩定性,降低應用的安全性
第三. 對開發人員要求會高很多
不過不用過于擔心,這些缺點,在第四種渲染方式上會得到緩解。等我下篇更新。
DNS 的作用就是通過域名查詢到具體的 IP。
因為 IP 存在數字和英文的組合(IPv6),很不利于人類記憶,所以就出現了域名。你可以把域名看成是某個 IP 的別名,DNS 就是去查詢這個別名的真正名稱是什么。
在 TCP 握手之前就已經進行了 DNS 查詢,這個查詢是操作系統自己做的。當你在瀏覽器中想訪問www.google.com時,會進行一下操作:
以上介紹的是 DNS 迭代查詢,還有種是遞歸查詢,區別就是前者是由客戶端去做請求,后者是由系統配置的 DNS 服務器做請求,得到結果后將數據返回給客戶端。
TCP握手
接下來是 TCP 握手,應用層會下發數據給傳輸層,這里 TCP 協議會指明兩端的端口號,然后下發給網絡層。網絡層中的 IP 協議會確定 IP 地址,并且指示了數據傳輸中如何跳轉路由器。然后包會再被封裝到數據鏈路層的數據幀結構中,最后就是物理層面的傳輸了。在這一部分中,可以詳細說下 TCP 的握手情況以及 TCP 的一些特性。
當 TCP 握手結束后就會進行 TLS 握手,然后就開始正式的傳輸數據。
TLS握手
數據在進入服務端之前,可能還會先經過負責負載均衡的服務器,它的作用就是將請求合理的分發到多臺服務器上,這時假設服務端會響應一個 HTML 文件。
首先瀏覽器會判斷狀態碼是什么,如果是 200 那就繼續解析,如果 400 或 500 的話就會報錯,如果 300 的話會進行重定向,這里會有個重定向計數器,避免過多次的重定向,超過次數也會報錯。
瀏覽器開始解析文件
瀏覽器開始解析文件,如果是 gzip 格式的話會先解壓一下,然后通過文件的編碼格式知道該如何去解碼文件。
構建 DOM 樹、構建 CSSOM 樹、解析JS
文件解碼成功后會正式開始渲染流程,先會根據 HTML 構建 DOM 樹,有 CSS 的話會去構建 CSSOM 樹。如果遇到 script 標簽的話,會判斷是否存在 async 或者 defer ,前者會并行進行下載并執行 JS,后者會先下載文件,然后等待 HTML 解析完成后順序執行。
如果以上都沒有,就會阻塞住渲染流程直到 JS 執行完畢。遇到文件下載的會去下載文件,這里如果使用 HTTP/2 協議的話會極大的提高多圖的下載效率。
生成 Render 樹
CSSOM 樹和 DOM 樹構建完成后會開始生成 Render 樹,這一步就是確定頁面元素的布局、樣式等等諸多方面的東西
調用 GPU 繪制,合成圖層,將內容顯示在屏幕上了
在生成 Render 樹的過程中,瀏覽器就開始調用 GPU 繪制,合成圖層,將內容顯示在屏幕上了。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。