模板

1. jinja2簡介

  • Jinja2:是 Python 下一個被普遍應用的模板引擎,是由Python實現的模板語言,他的設計思想來源於 Django 的模板引擎,並擴展了其語法和一系列強大的功能,其是Flask內置的模板語言。
  • 模板語言:是一種被設計來自動生成文檔的簡單文本格式,在模板語言中,通常都會把一些變量傳給模板,替換模板的特定位置上預先定義好的佔位變量名。
  • {{}} 來表示變量名,這種 {{}} 語法叫作變量代碼塊
  • 用 {%%} 定義的控制代碼塊,能夠實現一些語言層次的功能,好比循環或者if語句
  • 使用 {# #} 進行註釋,註釋的內容不會在html中被渲染出來

2. 過濾器

  • 過濾器的使用方式爲:變量名 | 過濾器。

{{variable | filter_name(*args)}}html

  • 若是沒有任何參數傳給過濾器,則能夠把括號省略掉

{{variable | filter_name}}python

常見內建過濾器

字符串操做

safe:禁用轉義sql

<p>{{ '<em>hello</em>' | safe }}</p>express

capitalize:把變量值的首字母轉成大寫,其他字母轉小寫flask

<p>{{ 'hello' | capitalize }}</p>api

lower:把值轉成小寫安全

<p>{{ 'HELLO' | lower }}</p>bash

upper:把值轉成大寫cookie

<p>{{ 'hello' | upper }}</p>session

title:把值中的每一個單詞的首字母都轉成大寫

<p>{{ 'hello' | title }}</p>

reverse:字符串反轉

<p>{{ 'olleh' | reverse }}</p>

format:格式化輸出

<p>{{ '%s is %d' | format('name',17) }}</p>

striptags:渲染以前把值中全部的HTML標籤都刪掉

<p>{{ '<em>hello</em>' | striptags }}</p>

truncate: 字符串截斷

<p>{{ 'hello every one' | truncate(9)}}</p>

列表操做

first:取第一個元素

<p>{{ [1,2,3,4,5,6] | first }}</p>

last:取最後一個元素

<p>{{ [1,2,3,4,5,6] | last }}</p>

length:獲取列表長度

<p>{{ [1,2,3,4,5,6] | length }}</p>

sum:列表求和

<p>{{ [1,2,3,4,5,6] | sum }}</p>

sort:列表排序

<p>{{ [6,2,3,1,5,4] | sort }}</p>

3. 控制代碼塊

控制代碼塊主要包含兩個:

  • if/else if /else / endif
  • for / endfor if語句

Jinja2 語法中的if語句跟 Python 中的 if 語句類似,後面的布爾值或返回布爾值的表達式將決定代碼中的哪一個流程會被執行:

{%if user.is_logged_in() %}
    <a href='/logout'>Logout</a>
{% else %}
    <a href='/login'>Login</a>
{% endif %}

# 咱們能夠在 Jinja2 中使用循環來迭代任何列表或者生成器函數
{% for post in posts %}
    <div>
        <h1>{{ post.title }}</h1>
        <p>{{ post.text | safe }}</p>
    </div>
{% endfor %}
複製代碼
  • 在一個 for 循環塊中你能夠訪問這些特殊的變量:

4. 模板代碼複用

4.1 宏

  • 把它看做 Jinja2 中的一個函數,它會返回一個模板或者 HTML 字符串
  • 爲了不反覆地編寫一樣的模板代碼,出現代碼冗餘,能夠把他們寫成函數以進行重用
  • 須要在多處重複使用的模板代碼片斷能夠寫入單獨的文件,再包含在全部模板中,以免重複
# 定義宏
{% macro input(name,value='',type='text') %}
    <input type="{{type}}" name="{{name}}"
        value="{{value}}" class="form-control">
{% endmacro %}

# 調用宏
{{ input('name' value='zs')}}

# 輸出
<input type="text" name="name"
    value="zs" class="form-control">
複製代碼

4.2 繼承

# 父模板
base.html
{% block top %}
  頂部菜單
{% endblock top %}

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

{% block bottom %}
  底部
{% endblock bottom %}

# 子模板
extends指令聲明這個模板繼承自哪
{% extends 'base.html' %}
{% block content %}
 須要填充的內容
{% endblock content %}
複製代碼

模板繼承使用時注意點:

  • 不支持多繼承
  • 爲了便於閱讀,在子模板中使用extends時,儘可能寫在模板的第一行。
  • 不能在一個模板文件中定義多個相同名字的block標籤。
  • 當在頁面中使用多個block標籤時,建議給結束標籤起個名字,當多個block嵌套時,閱讀性更好。

4.3 包含

代碼重用的功能,包含(Include)。它的功能是將另外一個模板整個加載到當前模板中,並直接渲染。

# include的使用
{% include 'hello.html' %}
包含在使用時,若是包含的模板文件不存在時,程序會拋出TemplateNotFound異常,能夠加上 ignore missing 關鍵字。若是包含的模板文件不存在,會忽略這條include語句。

# include 的使用加上關鍵字ignore missing
{% include 'hello.html' ignore missing %}
複製代碼

4.4 小結

  • 宏(Macro)、繼承(Block)、包含(include)均能實現代碼的複用。
  • 繼承(Block)的本質是代碼替換,通常用來實現多個頁面中重複不變的區域。
  • 宏(Macro)的功能相似函數,能夠傳入參數,須要定義、調用。
  • 包含(include)是直接將目標模板文件整個渲染出來。

5. 特有函數和變量

  1. config
# 能夠從模板中直接訪問Flask當前的config對象:

{{config.SQLALCHEMY_DATABASE_URI}}
sqlite:///database.db
複製代碼
  1. request
# 就是flask中表明當前請求的request對象:

{{request.url}}
http://127.0.0.1
複製代碼
  1. session
爲Flask的session對象

{{session.new}}
True
複製代碼
  1. g變量
在視圖函數中設置g變量的 name 屬性的值,而後在模板中直接能夠取出

{{ g.name }}
複製代碼
  1. url_for()
url_for會根據傳入的路由器函數名,返回該路由對應的URL,在模板中始終使用url_for()就能夠安全的修改路由綁定的URL,則不比擔憂模板中渲染出錯的連接:

{{url_for('home')}}

# 若是咱們定義的路由URL是帶有參數的,則能夠把它們做爲關鍵字參數傳入url_for(),Flask會把他們填充進最終生成的URL中:

{{ url_for('post', post_id=1)}}
/post/1
複製代碼
  1. get_flashed_messages()
這個函數會返回以前在flask中經過flask()傳入的消息的列表,flash函數的做用很簡單,能夠把由Python字符串表示的消息加入一個消息隊列中,再使用get_flashed_message()函數取出它們並消費掉:

{%for message in get_flashed_messages()%}
    {{message}}
{%endfor%}
複製代碼

6. Flask-WTF表單

  • 使用 Flask-WTF 實現表單

  • 配置參數,關閉 CSRF 校驗

app.config['WTF_CSRF_ENABLED'] = False

  • CSRF:跨站請求僞造

模板頁面:

<form method="post">
    {{ form.username.label }} {{ form.username }}<br/>
    {{ form.password.label }} {{ form.password }}<br/>
    {{ form.password2.label }} {{ form.password2 }}<br/>
    {{ form.submit }}
</form>
複製代碼

視圖函數:

from flask import Flask,render_template, flash
#導入wtf擴展的表單類
from flask_wtf import FlaskForm
#導入自定義表單須要的字段
from wtforms import SubmitField,StringField,PasswordField
#導入wtf擴展提供的表單驗證器
from wtforms.validators import DataRequired,EqualTo


app = Flask(__name__)
app.config['SECRET_KEY']='SECRET_KEY'

#自定義表單類,文本字段、密碼字段、提交按鈕
class RegisterForm(FlaskForm):
    username = StringField("用戶名:", validators=[DataRequired("請輸入用戶名")], render_kw={"placeholder": "請輸入用戶名"})
    password = PasswordField("密碼:", validators=[DataRequired("請輸入密碼")])
    password2 = PasswordField("確認密碼:", validators=[DataRequired("請輸入確認密碼"), EqualTo("password", "兩次密碼不一致")])
    submit = SubmitField("註冊")

#定義根路由視圖函數,生成表單對象,獲取表單數據,進行表單數據驗證
@app.route('/demo2', methods=["get", "post"])
def demo2():
    register_form = RegisterForm()
    # 驗證表單
    if register_form.validate_on_submit():
        # 若是代碼能走到這個地方,那麼就代碼表單中全部的數據都能驗證成功
        username = request.form.get("username")
        password = request.form.get("password")
        password2 = request.form.get("password2")
        # 僞裝作註冊操做
        print(username, password, password2)
        return "success"
    else:
        if request.method == "POST":
            flash("參數有誤或者不完整")

    return render_template('temp_register.html', form=register_form)

if __name__ == '__main__':
    app.run(debug=True)
複製代碼

7. CSRF

CSRF全拼爲Cross Site Request Forgery,譯爲跨站請求僞造。

  • 即用戶訪問了一個存在漏洞的網站A,在未退出登陸的同時訪問B攻擊網站,B攻擊網站會誘導用戶作一些操做,提交這些操做的同時,B網站會攜帶cookie跳轉訪問A網站,A網站會認爲用戶訪問,贊成B網站的請求,B網站攻擊成功。

8. 藍圖

藍圖/Blueprint對象用起來和一個應用/Flask對象差很少,最大的區別在於一個藍圖對象沒有辦法獨立運行,必須將它註冊到一個應用對象上才能生效

使用藍圖能夠分爲三個步驟:

# 1.建立一個藍圖對象
admin=Blueprint('admin',__name__)
# 2.在這個藍圖對象上進行操做,註冊路由,指定靜態文件夾,註冊模版過濾器
@admin.route('/')
def admin_home():
    return 'admin_home'
# 3.在應用對象上註冊這個藍圖對象
app.register_blueprint(admin,url\_prefix='/admin')
當這個應用啓動後,經過/admin/能夠訪問到藍圖中定義的視圖函數
複製代碼

藍圖的url前綴

  • 當咱們在應用對象上註冊一個藍圖時,能夠指定一個url_prefix關鍵字參數(這個參數默認是/)

  • 在應用最終的路由表url_map中,在藍圖上註冊的路由URL自動被加上了這個前綴,這個能夠保證在多個藍圖中使用相同的URL規則而不會最終引發衝突,只要在註冊藍圖時將不一樣的藍圖掛接到不一樣的自路徑便可

  • url_for

url_for('admin.index') # /admin/

9. 單元測試

測試從軟件開發過程能夠分爲:

  • 單元測試: 對單獨的代碼塊(例如函數)分別進行測試,以保證它們的正確性
  • 集成測試: 對大量的程序單元的協同工做狀況作測試
  • 系統測試: 同時對整個系統的正確性進行檢查,而不是針對獨立的片斷

斷言語句相似於:

raise AssertionError
 AssertionError
複製代碼

經常使用的斷言方法:

assertEqual     若是兩個值相等,則pass
assertNotEqual  若是兩個值不相等,則pass
assertTrue      判斷bool值爲True,則pass
assertFalse     判斷bool值爲False,則pass
assertIsNone    不存在,則pass
assertIsNotNone 存在,則pass
複製代碼
相關文章
相關標籤/搜索