Flask 入門(第一篇)

1. 認識 Flask

Flask 是一個微型 Web 框架,依賴於 jinjia2 模板系統和 Werkzeug WSGI(本質爲 Socket 服務端) 服務,默認狀況不支持數據庫抽象層、表單驗證,若是要使用能夠進行拓展。css

Flask 經常使用擴展包:html

  • Flask-SQLalchemy:操做數據庫;
  • Flask-migrate:管理遷移數據庫;
  • Flask-Mail:郵件;
  • Flask-WTF:表單;
  • Flask-script:插入腳本;
  • Flask-Login:認證用戶狀態;
  • Flask-RESTful:開發REST API的工具;
  • Flask-Bootstrap:集成前端Twitter Bootstrap框架;
  • Flask-Moment:本地化日期和時間;

安裝:前端

pip3 install flask

Werkzeug:python

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)

嚐鮮:shell

from flask import Flask

app = Flask(__name__)


@app.route("/")
def index():
    return "Index Page"


if __name__ == "__main__":
    app.run()

官網地址:數據庫

2. 路由系統

2.1 五種經常使用路由

Flask 經常使用五種路由:flask

# 前四種能夠接收變量
@app.route('/user/<username>')      # /user/rose
@app.route('/post/<int:post_id>')   # /post/1
@app.route('/post/<float:post_id>') # /post/1.2
@app.route('/post/<path:subpath>')     # /post/static/css/xx.css
@app.route('/login', methods=['GET', 'POST'])

示例:bootstrap

@app.route('/user/<username>')
def show_user_profile(username):
    
    return 'User %s' % username

以上五種路由基於如下對應關係:segmentfault

DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}

讓 Flask 支持正則:https://segmentfault.com/q/1010000000125259api

2.2 反解 URL

url_for() 方法能夠根據視圖函數名,反解出 url,相似於 Django 的 reverse() 方法:

# 接收視圖函數名字,返回所對應的絕對 URL
url_for('index', _external=True)
from flask import Flask, redirect, url_for

app = Flask(__name__)


@app.route("/")
def index():
    return "Index Page"

@app.route("/hello")
def hello():
    return "Hello World!"


@app.route('/user/<username>')
def profile(username):
    return username

with app.test_request_context():
    print(url_for('hello'))
    print(url_for('profile', username='rose'))
    print(url_for('index'))

if __name__ == "__main__":
    app.run()

test_request_context() 告訴 Flask,即便咱們使用Python shell,它也會像處理請求同樣行事。

運行結果以下:

/hello
/user/rose
/

2.3 正則匹配

from flask import Flask
from werkzeug.routing import BaseConverter

class Regex_url(BaseConverter):
    def __init__(self,url_map,*args):
        super(Regex_url,self).__init__(url_map)
        self.regex = args[0]

app = Flask(__name__)
app.url_map.converters['re'] = Regex_url

@app.route('/user/<re("[a-z]{3}"):id>')
def hello_itcast(id):
    return 'hello %s' % id


if __name__ == '__main__':
    app.run()

3. 模板系統

3.1 靜態文件和模板路徑設置

from flask import Flask, redirect, url_for, render_template

app = Flask(__name__)       # 靜態文件和模板依賴這句

@app.route('/hello/')
def hello():
    return render_template('t1.html')


if __name__ == '__main__':
    app.run()

靜態文件語法:

url_for('static', filename='style.css')

靜態文件目錄 static 在項目根目錄,與程序同級(須要本身建立),Flask 默認回會去 static 中查找,你能夠在裏面新建子文件夾:

<img src="{{ url_for('static', filename='imgs/1.png') }}">

模板路徑設置

Flask 會在 templates 文件夾裏尋找模板。因此,若是你的應用是個模塊,這個文件夾應該與模塊同級;若是它是一個包,那麼這個文件夾做爲包的子目錄:

狀況 1: 模塊:

/application.py
/templates
    /hello.html

狀況 2: 包:

/application
    /__init__.py
    /templates
        /hello.html

3.2 模板語言及自定義模板

Flask 使用的是 Jinja2模板,與 Django 同樣,所以語法也沒什麼差異。

自定義模板

在模板中使用 Python 函數:

app.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template

app = Flask(__name__)


def func():

    return '<h1>Flask 自定義模板</h1>'


@app.route('/index', methods=['GET', 'POST'])
def index():
    return render_template('index.html', func=func)

if __name__ == '__main__':
    app.run()

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ func() | safe }}			<!-- safe 不轉義 -->
</body>
</html>

3.3 過濾器

語法:

變量名 | 過濾器

字符串過濾器:

# 禁用轉義 safe
<p>{{ '<em>hello</em>' | safe }}</p>


# capitalize:把變量值的首字母轉成大寫,其他字母轉小寫;
<p>{{ 'hello' | capitalize }}</p>

# lower:把值轉成小寫;
<p>{{ 'HELLO' | lower }}</p>

# upper:把值轉成大寫;
<p>{{ 'hello' | upper }}</p>

# title:把值中的每一個單詞的首字母都轉成大寫;
<p>{{ 'hello' | title }}</p>

#trim:把值的首尾空格去掉;
<p>{{ ' hello world ' | trim }}</p>

# reverse:字符串反轉;
<p>{{ 'olleh' | reverse }}</p>

# format:格式化輸出;
<p>{{ '%s is %d' | format('name',17) }}</p>

# striptags:渲染以前把值中全部的HTML標籤都刪掉;
<p>{{ '<em>hello</em>' | striptags }}</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>

自定義過濾器

過濾器的本質是函數,兩種實現方式:一種是經過Flask應用對象的add_template_filter方法。還能夠經過裝飾器來實現自定義過濾器,與內置過濾器重名則覆蓋:

一、add_template_filter,第一個參數是函數名,第二個參數是自定義的過濾器名稱

def filter_double_sort(ls):
    return ls[::2]
app.add_template_filter(filter_double_sort,'double_2')

二、裝飾器來實現自定義過濾器,參數爲過濾器名字:

@app.template_filter('db3')
def filter_double_sort(ls):
    return ls[::-3]

app.py

from flask import Flask, render_template

app = Flask(__name__)


def filter_double_sort(ls):
    return ls[::2]
app.add_template_filter(filter_double_sort, 'double_2')

@app.route('/')
def index():
    data_list = [1, 2, 5, 8]
    return render_template('index4.html', data_list=data_list)

if __name__ == "__main__":
    app.run()

index4.html

<p>{{ data_list | double_2}}</p>

3.5 宏

相似於 python 中的函數,宏的做用就是在模板中重複利用代碼,避免代碼冗餘。

定義不帶參數的宏:

<!-- 定義宏 -->
{% macro input() %}
  <input type="text" name="username" value="" size="30"/>
{% endmacro %}

<!-- 調用宏 -->
{{ input() }}

定義帶參數的宏:

{% macro input(name,value='',type='text',size=20) %}
    <input type="{{ type }}"
           name="{{ name }}"
           value="{{ value }}"
           size="{{ size }}"/>
{% endmacro %}

<!-- 調用宏,並傳遞參數 -->
{{ input(value='name',type='password',size=40)}}

還能夠把宏單獨抽取出來,封裝成 html 文件,其它模板中導入使用文件名能夠自定義 macro.html

{% macro function() %}

    <input type="text" name="username" placeholde="Username">
    <input type="password" name="password" placeholde="Password">
    <input type="submit">
{% endmacro %}

在其它模板文件中先導入,再調用:

{% import 'macro.html' as func %}
{% func.function() %}

宏、繼承(extend)和包含(include)區別:

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

3.4 特殊變量和方法

  • config 對象: Flask的config對象,也就是 app.config 對象,{{ config.SQLALCHEMY_DATABASE_URI }}
  • get_flashed_messages方法:應用在模板中通常用於獲取錯誤信息,返回以前在Flask中經過 flash() 傳入的信息列表。把字符串對象表示的消息加入到一個消息隊列中,而後經過調用 get_flashed_messages() 方法取出。
{% for message in get_flashed_messages() %}
    {{ message }}
{% endfor %}

4. 公共組件

4.1 請求和響應

一、請求 request

瀏覽器發送過來的 HTTP 請求,被 flask 封裝在 request中(werkzeug.wrappers.BaseRequest) 中,提供了一下字段或方法以供使用:

request.method			# 請求方法
request.args			# 獲取GET請求參數
request.form			# 獲取POST請求參數
request.values
request.files			# 獲取上傳文件
request.cookies			# cookies
request.headers			# 請求頭
request.path
request.full_path
request.script_root
request.url				# 請求 URL 
request.base_url		# 獲取請求路徑
request.url_root
request.host_url
request.host			# 獲取ip和端口

二、響應 response

一、模板渲染、重定向

模板渲染:render_template、重定向:redirecturl_for

from flask import Flask, render_template, request, redirect, url_for

app = Flask(__name__)

@app.route('/index/', method=['GET', 'POST'])
def index():
    return render_template('index.html')
    # redirect(url_for('login'))		# 重定向

二、錯誤信息

from flask import Flask, abort, render_template
app = Flask(__name__)


@app.route('/index/', methods=['GET', 'POST'])
def index():
    abort(404, 'Page Not Found!')		# 返回一個  Page Not Found! 的頁面

if __name__ == '__main__':
    app.run()

三、make_reponse

make_response 相似於 Django 的 HTTPResponse,用於返回字符串,下面是幾個比較常見的用法:

返回內容、頁面:

from flask import Flask, abort, render_template, make_response

app = Flask(__name__)

def func():
    return '<h1>Flask 自定義模板</h1>'

@app.route('/index/', methods=['GET', 'POST'])
def index():
    # return make_response('make response')			# 返回內容
    response = make_response(render_template('index.html', func=func))		# 返回頁面
    # return response, 200,			# 返回內容和狀態碼

responseflask.wrappers.Response 類型,同時 make_resposne 還能夠用來設置響應頭、設置 cookie 等:

# response.delete_cookie
# response.set_cookie
# response.headers['X-Something'] = 'A value'
@app.route('/index/', methods=['GET', 'POST'])
def index():
    response = make_response(render_template('index.html', func=func))
    response.headers['hahaha'] = 'hello world'
    return response

4.2 自定義錯誤頁面

若是在瀏覽器中輸入不可用的路由,那麼就會顯示一個 404 狀態的錯誤頁面,這個頁面太過簡陋、平庸,並非咱們所但願的。好在 Flask 容許咱們基於模板自定義錯誤頁面,須要用到模塊:flask-bootstrap

安裝:

pip3 install flask-bootstrap

下面來示範兩個最多見的錯誤:404 和 500:

一、app.py

初始化 bootstrap,定義兩個函數,用於處理 404 和 500 錯誤頁面:

from flask import Flask, abort, render_template
from flask_bootstrap import Bootstrap


app = Flask(__name__)
bootstrap = Bootstrap(app)		# 初始化,千萬別忘記

@app.route('/index/', methods=['GET', 'POST'])
def index():
    return "OK"

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'),404

@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'),500

if __name__ == '__main__':
    app.run()

二、在模板中定義一個母版 templates/errors/base.html,編輯以下:

{%extends "bootstrap/base.html"%}

{%block title %}Flask{% endblock %}

{%block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle"
            data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>

{% endblock %}
{% block content %}
<div class="container">
    <div class="page-header">
        {% block page_content %}{% endblock %}
    </div>
</div>
{% endblock %}

三、下面再編寫 404.html500.html

404.html

{% extends "base.html" %}
{% block title %}Flasky - Page Not Found{% endblock %}
{% block page_content %}
<div class="page-header">
    <h1>Not Found</h1>
</div>
{% endblock %}

500.html

{% extends "base.html" %}
{% block title %}Flasky - internal server error{% endblock %}
{% block page_content %}
<div class="page-header">
    <h1>internal server error</h1>
</div>
{% endblock %}

如今咱們來訪問一個不存在的頁面看看:http://127.0.0.1:5000/main/

彷佛好看了點,固然你還能夠定製更爲高端一點。

4.3 Session

Session 依賴於 Cookies ,而且對 Cookies 進行密鑰簽名要使用會話,你須要設置一個密鑰。

  • 設置:session['username'] = 'xxx'
  • 刪除:session.pop('username', None)
  • 獲取:session.get('username')

設置獲取 Cookie

from flask import Flask,make_response
@app.route('/cookie')
def set_cookie():
    resp = make_response('this is to set cookie')
    resp.set_cookie('username', 'itcast')
    return resp

from flask import Flask,request
#獲取cookie
@app.route('/request')
def resp_cookie():
    resp = request.cookies.get('username')
    return resp

示例:利用 Session 驗證用戶登陸

from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)


@app.route('/')
def index():
    if 'username' in session:
        return '歡迎回來: %s' % escape(session['username'])
    return '你沒有登陸'		# 也能夠重定向到登陸頁面


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''
        <form action="" method="post">
            <p><input type=text name=username>
            <p><input type=submit value=Login>
        </form>
    '''


@app.route('/logout')
def logout():
    # 從 session 移除 username
    session.pop('username', None)
    return redirect(url_for('index'))


# 設置密鑰
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'


if __name__ == '__main__':
    app.run()

4.3 message

message 是一個基於 Session 實現的用於保存數據的集合,其特色是:使用一次就刪除

app.py

from flask import Flask, flash, redirect, render_template, request

app = Flask(__name__)
app.secret_key = 'some_secret'


@app.route('/')
def index1():
    return render_template('index2.html')


@app.route('/set')
def index2():
    v = request.args.get('p')
    flash(v)        # 將消息給下一個請求,並將其刪除,模板必須調用 get_flashed_messages() 函數
    return 'ok'


if __name__ == "__main__":
    app.run()

index2.html

模板中必須使用 get_flashed_messages() 才能獲取到 message 傳遞的信息:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>messages</title>
</head>
<body>
    {% with messages = get_flashed_messages() %}		<!-- with xxx:取別名 -->
        {% if messages %}
        <ul class=flashes>
            {% for message in messages %}
            <li>{{ message }}</li>
            {% endfor %}
        </ul>
        {% endif %}
    {% endwith %}
</body>
</html>

首先請求:http://127.0.0.1:5000/set?p=123index() 函數獲取 p 的值,並將其傳遞給下一個請求(傳遞後即將其刪除)。

第二個請求訪問:http://127.0.0.1:5000/,從而得到上一次請求傳遞的信息:

4.4 請求鉤子

所謂請求鉤子便是用來處理請求前、後,一些特定事情的功能實現。如:請求前鏈接數據庫、請求後指定數據交互格式等。Flask 中請求鉤子以裝飾器形式實現:

Flask 中請求鉤子:

  • before_first_request:在處理第一個請求前運行,好比:數據庫的鏈接,初始化操做
  • before_request:在每次請求前運行。
  • after_request:若是沒有未處理的異常拋出,在每次請求後運行。
  • teardown_request:在每次請求後運行,即便有未處理的異常拋出。

示例:基於 before_request 實現用戶登陸認證

相比較裝飾器而已有以下優點:

  • 裝飾器實現用戶登陸認證,須要給每一個須要認證的視圖函數添加裝飾器
  • before_request,只需一個便可。
from flask import Flask, render_template, request, redirect, session, url_for

app = Flask(__name__)

app.secret_key = "123$456"

# 基於flask裏請求擴展來作
@app.before_request
def process_request(*args, **kwargs):
    """無論訪問哪一個視圖函數,都會實現執行這個函數,也就意味着每次都會檢查是否登陸"""
    # 訪問/login的時候尚未登陸,就會一直重定向到登陸頁,因此就要設置個白名單,若是請求地址是/login,就返回None
    if request.path == "/login":
        return None

    # 1.登陸驗證功能
    user = session.get('user_info')
    # 2.若是登陸信息正常,什麼都不作,程序繼續其餘執行
    if user:
        return None
    # 3.若是登陸驗證不經過,就重定向到登陸頁面
    return redirect("/login")


@app.route("/index", methods=['GET'])
def index():
    name = session.get('user_info', None)
    return 'Welcome, %s' % name


@app.route("/login", methods=['GET', 'POST'])
def login():
    if request.method == "GET":
        return render_template("login.html")
    else:
        user = request.form.get("username")
        pwd = request.form.get("password")
        if user == "rose" and pwd == "123456":
            session['user_info'] = user
            return redirect("/index")

        return render_template("login.html", **{"error": "用戶名和密碼錯誤"})


if __name__ == "__main__":
    app.run()

也能夠有多個請求鉤子,可是要注意的是當有多個請求中間件時,執行順序是不一樣的:

  • before_request:從上到下按照順序執行
  • after_request:從下到上的順序執行
  • 當有多個 before_request 時,若第一個有 return 語句,那麼後面的 before_request 將被攔截不被執行,可是 after_request 會繼續執行

4.5 中間件

Flask 程序在運行過程當中會事先加載 wsgi_app,基於此咱們能夠拓展作些別的事情:

from flask import Flask
app = Flask(__name__)

@app.route("/login", methods=['GET', 'POST'])
def index():
    pass

class Md(object):
    def __init__(self, old_wsgi_app):
        self.old_wsgi_app = old_wsgi_app

    def __call__(self, environ, start_response):
        print("開始以前")
        ret = self.old_wsgi_app(environ, start_response)
        print("結束以後")
        return ret

if __name__ =="__main__":
    app.wsgi_app = Md(app.wsgi_app) # 至關於把wsgi_app給更新了
    app.run()

5. 表單

5.1 表單拓展 WTForms

表單由三個部分組成:表單標籤、表單域、表單按鈕。Flask 經過Flask-WTF 實現表單功能。它封裝了WTForms,能夠生成表單、以及驗證表單數據。

安裝:

pip3 install Flask-WTF
pip3 install flask-moment

WTForms 支持的 HTML 標準字段:

StringField	    # 文本字段
TextAreaField	# 多行文本字段
PasswordField	# 密碼文本字段
HiddenField	    # 隱藏文本字段
DateField	    # 文本字段,值爲datetime.date格式
DateTimeField	# 文本字段,值爲datetime.datetime格式
IntegerField	# 文本字段,值爲整數
DecimalField	# 文本字段,值爲decimal.Decimal
FloatField	    # 文本字段,值爲浮點數
BooleanField	# 複選框,值爲True和False
RadioField	    # 一組單選框
SelectField	    # 下拉列表
SelectMultipleField	    # 下拉列表,可選擇多個值
FileField	    # 文本上傳字段
SubmitField	    # 表單提交按鈕
FormField	    # 把表單做爲字段嵌入另外一個表單
FieldList	    # 一組指定類型的字段

WTForms 經常使用驗證函數:

驗證函數 說明
DataRequired 確保字段中有數據
AEqualTo 比較兩個字段的值,經常使用於比較兩次密碼輸入
Length 驗證輸入的字符串長度
NumberRange 驗證輸入的值在數字範圍內
URL 驗證URL
AnyOf 驗證輸入值在可選列表中
NoneOf 驗證輸入值不在可選列表中

跨站請求僞造保護 csrf

設置一個密匙,生成加密令牌,再用令牌驗證請求表單中數據真僞:

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'  # 密匙隨便取 

# 若是你設置的模板中存在表單,你只須要在表單中添加以下
<form method="post" action="/">
    {{ form.csrf_token }}
</form>

# 若是沒有模板中沒有表單,你仍然須要一個 CSRF 令牌
<form method="post" action="/">
    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>

簡單示例

一、定義一個表單類:

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

# validators 不能爲空
class NameForm(FlaskForm):
    name = StringField(label='用戶名', validators=[Required()])
    submit = SubmitField('提交')

二、在模板中使用表單:

<h1>Hello, {% if name %}{{ name }} {% else %} Stranger {% endif %}!</h1>

<form method='post'>
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{form.name() }}
    {{ form.submit() }}

    # 傳入 HTML 屬性
    {{ form.name.label }} {{form.name(id='id_name') }}
</form>

老是本身傳屬性太麻煩,並且表單樣式過於醜陋。能夠用 flask-bootstrap,它是對 bootstrap 進行了簡單封裝,安裝好以後能夠直接調用:

<!--上面表單可用下面方式一次渲染-->
{% import 'bootstrap/wtf.html' as wtf %}
{{ wtf.quick_form(form) }}
from flask_bootstrap import Bootstrap
app = Flask(__name__)

bootstrap = Bootstrap(app)

wtf.quick_form(form) 函數參數爲 Flask-WTF 表單對象

<!-- 條件結果爲 True,渲染 if else 中文字,不然渲染 else endif 中語句 -->
<h1>Hello, {% if name %}{{ name }} {% else %} Stranger {% endif %}!</h1>

5.2 基於 WTForms 實現用戶登陸驗證

實現方式:繼承+WTForms +Flask-Bootstrap

app.py

from flask import Flask, render_template, redirect, url_for, session, request,flash
from flask_bootstrap import Bootstrap
from flask_moment import Moment

#導入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'] = '1'

bootstrap = Bootstrap(app)  # 使用 bootstrap 渲染表單
moment = Moment(app)    # 本地化時間

#自定義表單類,文本字段、密碼字段、提交按鈕
class Login(FlaskForm):
    user = StringField(label=u'用戶:', validators=[DataRequired()])
    pwd1 = PasswordField(label=u'密碼', validators=[DataRequired()])
    pwd2 = PasswordField(label=u'確認密碼', validators=[DataRequired()])
    submit = SubmitField(u'提交')

@app.route('/', methods=['GET','POST'])
def index():
    return render_template('index.html')

#定義根路由視圖函數,生成表單對象,獲取表單數據,進行表單數據驗證
@app.route('/login', methods=['GET','POST'])
def login():
    form = Login()
    if form.validate_on_submit():
        name = form.user.data
        pwd1 = form.pwd1.data
        pwd2 = form.pwd2.data
        print(name, pwd1, pwd2)

        if name == 'rose' and (pwd1 == pwd2 and pwd2 == '123'):
            return redirect(url_for('index'))
        else:
            flash(u'用戶名或密碼錯誤!')

    return render_template('login.html',  form=form)

if __name__ == '__main__':
    app.run()

include/base.html

{% extends "bootstrap/base.html" %}

{% block title %}Flask WTF{% endblock %}

{% block head %}
{{ super() }}
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
{% endblock %}

{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flask WTF</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class="container">
    <!-- get_flashed_messages() 顯示錯誤信息 -->

    {% for message in get_flashed_messages() %}
    <div class="alert alert-warning">
        <button type="button" class="close" data-dismiss="alert">&times;</button>
        {{ message }}
    </div>
    {% endfor %}

    {% block page_content %}{% endblock %}
</div>
{% endblock %}

{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}

login.html

繼承 base.html

{% extends "include/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}Flask WTF{% endblock %}

{% block page_content %}
<div class="page-header">

</div>
{{ wtf.quick_form(form) }}
{% endblock %}

將用戶我的信息保存到會話中:

app.py

from flask import Flask, render_template, redirect, url_for, session, request,flash


def login('/login', methods=['GET', 'POST']):
    ...
    # 會話中原有值
    old_name = session.get('name')
    if old_name is not None and old_name != form.name.data:
        flash('用戶名錯誤!')
    session['name'] = form.name.data
    return redirect(url_for('index'))
 return render_template('login.html', form=form, name=session.get('name'))

login.html

<div class="page-header">
    <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>

相關文章
相關標籤/搜索