07.flask博客項目實戰二之模板使用


配套視頻教程

本文B站配套視頻教程

模板定義

如有一個預期:html主頁有一個 歡迎用戶的標題。目前這個應用程序還沒用戶的概念,也沒用戶系統。但可用一個 模擬用戶,用Python字典實現:

user = {'username':'Miguel'}

創建模擬對象 是一種有用的技術,使我們可專注於應用程序已有的部分,而不必擔心尚不存在的部分。
app/routes.py:從視圖函數中返回完整的HTML頁面

from app import app

@app.route('/')
@app.route('/index')
def index():
	user = {'username':'Miguel'}
	return '''
<html>
	<head>
		<title>Home Page - Microblog</title>
	<head>
	<body>
		<h1>Hello,''' + user['username']+ '''!</h1>
	<body>
</html>
'''

在cmd中運行程序。更新視圖功能,並查看應用程序在瀏覽器中的顯示效果。

C:\Users\Administrator>d:

D:\microblog>cd D:\microblog\venv\Scripts

D:\microblog\venv\Scripts>activate
(venv) D:\microblog\venv\Scripts>cd D:\microblog

(venv) D:\microblog>set FLASK_APP=microblog.py

(venv) D:\microblog>flask run
 * Serving Flask app "microblog.py"
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [02/Aug/2018 18:11:46] "GET / HTTP/1.1" 200 -

很明顯,HTML代碼 和.py代碼混在一起了,很不利於今后的維護、理解。就得將網絡布局(呈現)應用程序的邏輯處理代碼 分開/分離。模板在此閃亮登場!將助實現表示、業務邏輯的分離。

Flask中,模板是作為單獨的文件編寫的,存放在應用程序 包內的 templates文件夾(約定俗成命名為 templates)下。

即在app目錄下創建templates文件夾:

(venv) D:\microblog>cd D:\microblog\app

(venv) D:\microblog\app>mkdir templates

在此目錄下創建一個HTML文件index.html,它將和上方index()這個視圖函數一樣的視圖功能。
app/templates/index.html:主頁面模板

<html>
	<head>
		<title>{{ title }} - Microblog</title>
	</head>
	<body>
		<h1>Hello,{{ user.username }}!</h1>
	</body>
</html>

這是一個標准的、簡單的HTML頁面。但有一點跟我們寫HTML代碼不同是title標簽、h1標簽中的 {{ … }}兩對花括號,在此它是個 占位符,作用是將表達式(如文字、數學式子、比較運算符等,其實在Python中是一個Python語句)打印到模板進行輸出。具體參考Jinja2官網文檔
這些占位符表示HTML頁面中可變的部分,並且只在運行時才知道。

現在HTML頁面的呈現已在HTML模板中了,這樣接着就可簡化一下視圖函數index()了。修改routes.py文件
app/routes.py:使用render_template()函數

from app import app
from flask import render_template#從flask包中導入render_template函數

@app.route('/')
@app.route('/index')
def index():
    user = {'username':'Miguel'}
    return render_template('index.html', title='Home', user=user)

將模板(index.html)轉換為完整HTML頁面的操作稱之為 呈現(render,譯作 遞交、表達、給予,在此譯作 “渲染”)。為了渲染模板,由從flask包中導入的render_template()完成,此函數“攜帶”模板文件名(index.html)、模板參數的變量列表,並返回相同的模板,不過其中所有占位符都替換為實際值。

render_template()函數調用與Flask框架捆綁在一起的Jinja2模板引擎。Jinja2會用相應的值替換{{ ... }}塊,這個相應的值由render_template()調用時提供的參數給出。
參考:flask.render_template()

控制結構----if條件、for循環、繼承

上述過程只是理解了:Jinja2模板引擎 如何在渲染過程中用實際值 替換 (模板中的)占位符。
接下來將認識到更多 Jinja2在模板文件中支持的更多強大操作:if條件、for循環、繼承等。
源自官網的這句話:

There are a few kinds of delimiters. The default Jinja delimiters are configured as follows:

{% ... %} for Statements
{{ ... }} for Expressions to print to the template output
{# ... #} for Comments not included in the template output
#  ... ## for Line Statements

if、for、繼承均在{% ... %}塊中寫控制語句。

if條件

形如:

		{% if title %}
			...語句塊
		{% else %}
			...語句塊
		{% endif %}

app/templates/index.html:模板中添加條件語句

<html>
    <head>
		{% if title %}
			<title>{{ title }} - Microblog</title>
		{% else %}
			<title>Welcome to Microblog!</title>
		{% endif %}
    </head>
    <body>
        <h1>Hello,{{ user.username }}!</h1>
    </body>
</html>

上述代碼中if語句塊的功能是:若視圖函數index()沒有傳遞title占位符變量的值,則index.html模板將會提供默認值(else語句塊中),而不是顯示空標題。
嘗試將routes.py中render_template()中的title='Home',刪除。效果:圖略

for循環

在模板中形如:

{% for post in posts %}
	...語句塊
{% endfor %}

需求:登錄用戶可在主頁中查看最新的帖子。
實現:
首先,用虛擬對象的方法來創建一些用戶、帖子,以供顯示。
app/routes.py:視圖函數中的假帖子

from app import app
from flask import render_template#從flask包中導入render_template函數

@app.route('/')
@app.route('/index')
def index():
    user = {'username':'Miguel'}#用戶
	posts = [#創建一個列表:帖子。里面元素是兩個字典,每個字典里元素還是字典,分別作者、帖子內容。
		{
			'author': {'username':'John'},
			'body':'Beautiful day in Portland!'
		},
		{
			'author': {'username':'Susan'},
			'body':'The Avengers movie was so cool!'
		}
	]
    return render_template('index.html', title='Home', user=user, posts=posts)

帖子列表 可包含任意數量的元素,由視圖函數index()決定將在頁面中顯示的帖子數量。而模板index.html不能假設這有多少個帖子,因此它需要准備好以通用方式呈現視圖發送來的盡可能多的帖子。在模板index.html中,用for循環遍歷所有的帖子並呈現。
app/templates/index.html:在模板中的for循環

<html>
    <head>
		{% if title %}
			<title>{{ title }} - Microblog</title>
		{% else %}
			<title>Welcome to Microblog!</title>
		{% endif %}
    </head>
    <body>
        <h1>Hello,{{ user.username }}!</h1>
		{% for post in posts %}
			<div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
		{% endfor %}
    </body>
</html>

運行程序,圖略

模板繼承

形如:

{% extends "base.html" %}

{% block content %}
	...
{% endblock %}

現在,大部分Web應用程序在頁面頂部有一個導航欄,它常包含一些常用鏈接:如登錄、退出、編輯個人資料等。可以很輕松地將導航欄添加到index.html模板,甚至更多的HTML頁面中。但隨着應用程序的增長(頁面數量的增多),這些頁面都將使用相同的導航欄,不可能每一個頁面都增加一份相同的導航欄代碼。

Jinja2具有模板繼承功能,完美解決上述問題。在實際操作中,將所有模板共有的頁面布局部分移至基礎模板中,其他模板則繼承自它。

實例:實現一個簡單的導航欄,其他模板繼承它。
app/templates目錄下創建一個基礎模板文件 base.html。
app/templates/base.html:帶導航欄的基礎模板

<html>
	<head>
		{% if title %}
			<title>{{ title }} - Microblog</title>
		{% else %}
			<title>Welcome to Microblog</title>
		{% endif %}
	</head>
	<body>
		<div>Microblog:<a href="/index">Home</a></div>
		<hr>
		{% block content %}
		{% endblock %}
	</body>
</html>

在上述基礎模板中,塊block 控制語句用於定義派生模板可自行插入的位置。塊block 被賦予唯一的名字 content派生模板在提供其內容時可引用這個名稱。

修改index.html這個模板,讓其繼承base.html模板。
app/templates/index.html:從基礎模板繼承

{% extends "base.html" %}

{% block content %}
	<h1>Hello,{{ user.username }}!</h1>
	{% for post in posts %}
		<div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
	{% endfor %}
{% endblock %}

base.html基礎模板 實現處理常規頁面的結構,則派生模板index.html簡化大部分內容。
extends語句 建立了兩個模板之間的繼承關系,因此,Jinja2就會知道:當它被要求渲染index.html時,需要將其嵌入base.html中。這倆模板具有匹配的block語句 名稱content,這就是Jinja2如何將兩個模板合並為一個模板的方法。
image.png

運行程序,圖略

今后,當再需要為應用程序創建其他頁面時,就可省去編寫相同代碼的麻煩,並讓應用程序的所有頁面共享相同的外觀,而只需一個步驟:創建繼承自base.html模板的派生模板

目前為止,項目結構:

microblog/
	venv/
	app/
		templates/
			base.html
			index.html
		__init__.py
		routes.py
	microblog.py

參考
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-ii-templates


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM