1. 程式人生 > >web開發之flask簡介

web開發之flask簡介

文章目錄


flask是一個很簡易的web框架,接下來我們將一步步建立一個完整的網站服務。
使用如下程式碼安裝flask

pip install flask

啟動服務的方法:

export FLASK_APP=schedule.py
export FLASK_DEBUG=True
flask run --debugger --host=0.0.0.0

上面的程式碼是可除錯的,如果要正式釋出,則應該將debug相關內容刪除。
最後的–host部分使得服務可以遠端訪問。

1. 基本概念

1.1 初始化

建構函式的__name__變數決定程式的根目錄。

from flask import Flask
app = Flask(__name__)

1.2 路由和檢視函式

客戶端的URL需要轉換為伺服器的python函式,其對映關係稱為路由,使用app.route修飾器可以將函式進行註冊,被註冊的函式稱為檢視函式。
此外,也可以使用app.add_url_rule()生成對映。
檢視函式可以帶引數,預設為string型別,也可以指定為int,float,path型別,使用<int: id>的方式。參考下面的例子:

@app.route('/')
def index()
	return '<h1>Hello World!</h1>'

@app.route('/user/<name>')
def user(name):
	return '<h1>Hello, %s</h1>' % name

1.3 上下文

Flask使用上下文訪問客戶端返回的http請求物件。上下文分為以下四種:

變數 上下文 說明
current_app 程式 啟用程式的例項
g 程式 處理請求時用作臨時儲存的物件
request 請求 請求物件,封裝了客戶端發出的額HTTP請求中的內容
session 請求 使用者會話,儲存需要記住的值的詞典。session在關閉瀏覽器之後失效

無論是哪一個,在使用之前都要先引入:

from flask import request,session

session的定義很簡單,下面是例子,注意使用get()方法比較安全,對於不存在的鍵,返回預設值None。

session['user'] = form.username.data
...
name = session.get('user')

request有post和get兩種方式,下面是例子:
模板程式碼:

$.ajax({
    type:'POST',
    url:"/saveAction",
    contentType:'application/json; charset=UTF-8',
    data:JSON.stringify({'clng':lng,'clat':lat}),
    dataType:'json'
})
        
$.get('/getGeo',{lat:clat,lng:clng},function(data){
    var d = data;
})

後臺python程式碼:

import mzgeohash as geo
@app.route('/getGeo')
def getGeo():
    lat = float(request.args.get('lat'))
    lng = float(request.args.get('lng'))
    return  geo.encode((lng,lat))[:7]

@app.route('/saveAction', methods=['POST'])
def saveAction():
    d = json.loads(request.get_data())
    lat =  float(d['lat'])
    lng =  float(d['lng'])
    session['lat'] = lat
    session['lng'] = lng
    return 'success'

1.4 響應和重定向

可以使用make_response方法封裝響應,可以接受作為html頁面返回的字串、裝填嗎和header字典。使用make_response還有一個好處是可以設定cookie:

resp = make_response("set cookie OK")
resp.set_cookie("settime","python2",max_age=3600)

使用redirect可以執行重定向的響應,如下:

from flask import redirect,url_for
@app.route('/')
def index():
	return redirect(url_for('login'))

其中url_for接收檢視函式名,返回對應的url。

1.5 Flash訊息傳遞

Flash是隻顯示一次的資料。使用前需要import。
使用方法很簡單,下面是例子:

flash('you changed your name')

然後在模板中使用get_flashed_messages方法獲得訊息。使用for迴圈是因為訊息有可能會排隊。

{% for message in get_flashed_messages() %}
	{{message}}
{% endfor %}

2. 模板

模板指的是包含相應文字的檔案,包含用佔位變量表示的動態部分。Flask把靜態檔案放置在根目錄下的static資料夾下。注意要使用中文的話,需要在python程式碼最前面加上:

#coding=utf-8

然後在所有中文字串前面加上u。

2.1 渲染過程

使用真實值替換變數,再返回最終相應字串的過程稱為渲染
Flask使用Jinja2引擎,程式碼中使用render_template渲染模板。渲染時可以傳遞引數,參考如下程式碼:

from flask import render_template
...
@app.route('/user/<name>')
def user(name):
	return render_template('user.html',name = 'ie06')

這樣,模板中的name就會被替換為’ie06’。預設情況下,Flask在templates資料夾中尋找模板,變數用兩個中括號表示,示例如下:

<h1>Hello, {{name}}</h1>

可以為變數新增管道函式,例如
{{name|capitalize}},則name會變成’Ie06’

2.2 控制結構

使用{% %}新增控制結構。例如:

{% if user%}
    Hello, {{user}}!
{% else %}
    Hello, Stranger!
{% endif %}   
<ul>
	{% for comment in comments %}
		<li>{{comment}}</li>
	{% endfor %}
</ul>

另外有一個模板繼承的重要功能,首先定義個基礎模板base.html,中間新增

{% block body %}{% endblock %}

然後在衍生檔案中使用

{% extends "base.html" %}
{% block body %}...{% endblock %}

就可以將base.html中的內容載入到衍生檔案中了。

2.3 bootstrap

bootstrap是Twitter開發的一個開源框架,python下需要安裝,是一套非常好用的模板。

pip install flask-bootstrap

使用如下方法引入bootstrap模板:

from flask_bootstrap import Bootstrap
...
bootstrap = Bootstrap(app)

然後在模板中使用:

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

這裡有不少示例可供參考。

3. 表單

使用Flask-WTF建立表單。使用之前先用pip進行安裝。

3.1 啟用CSRF保護

設定一個金鑰,然後程式使用金鑰生成加密令牌,用於驗證表單中資料的真偽:

class Config(object):
    SECRET_KEY = '[email protected]#$%FSD'
app = Flask(__name__)
app.config.from_object(Config)

3.2 建立表單類

每個表單由一個表單類來表示,各種filed使用.data取出對應的值。
第一次訪問程式時,伺服器接收到的是沒有資料的GET請求,validate_on_submit返回False。填寫好內容並提交表單後,伺服器收到包含資料的POST請求,validate_on_submit返回True。
參考下面的程式碼:

from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,BooleanField,SubmitField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
    #DataRequired,當你在當前表格沒有輸入而直接到下一個表格時會提示你輸入
    username = StringField(unicode('使用者', encoding='utf-8'),validators=[DataRequired(message='input username')])
    password = PasswordField(unicode('密碼', encoding='utf-8'),validators=[DataRequired(message='input password')])
    remember_me = BooleanField(u'記住我')
    submit = SubmitField(u'登入')
@app.route('/',methods=['GET','POST'])
def login():
    form = LoginForm()
    result = u"請登入"
    if form.validate_on_submit(): 
    	result = u"歡迎你,"+ form.username.data
    	return redirect(url_for('mainpage',result = result))
    return render_template('login.html',title='登入',form=form, result = result)

然後在login.html中使用bootstrap模板進行渲染:

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="alert alert-warning">{{result}}</div>
<div class="col-md-4">
    {{ wtf.quick_form(form) }}
</div>
{% endblock %}

4. 資料庫

這裡用最最最簡單的sqlite,centos系統自帶。

4.1 ORM模型

使用flask_sqlalchemy建立ORM模型,用物件化的方法操作資料庫。使用之前需要安裝flask_sqlalchemy。
簡單例子如下:

from flask_sqlalchemy import SQLAlchemy
import sqlite3
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
    SQLALCHEMY_DATABASE_URI = 'sqlite:///'+os.path.join(basedir,'static/data.sqlite3')
    SQLALCHEMY_TRACK_MODIFICATIONS=True
    SQLALCHEMY_COMMIT_ON_TEARDOWN=True

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)

class User(db.Model):
    __tablename__='user'
    id = db.Column(db.Integer, primary_key = True)
    phone = db.Column(db.String(64),nullable=False)
    pw = db.Column(db.String(64),nullable=False)
    def __repr__(self):
        return '<User %r>'%self.phone

@app.route('/',methods=['GET','POST'])
def login():
    form = LoginForm()
    result = u"請登入"
    if form.validate_on_submit():        
        try:
            user = User.query.filter_by(phone=form.username.data).first()
            if user is None:
                result = u'沒有此使用者'
            else:
                if user.pw == form.password.data:
                    session['user'] = form.username.data
                    return redirect(url_for('schedule'))
                else:
                    result = u'密碼錯誤'
        except Exception as err:
            result = err
    return render_template('login.html',title='登入',form=form,result = result)

其中db物件表示建立了一個新的SQLAlchemy類的例項,使用這個物件可以建立資料庫、建立表、對錶進行資料增刪改查的操作。
既然是關係型資料庫,那麼表達關係是非常重要的內容,下面是上面例子的拓展:

class User(db.Model):
    __tablename__='user'
    id = db.Column(db.Integer, primary_key = True)
    phone = db.Column(db.String(64),nullable=False)
    pw = db.Column(db.String(64),nullable=False)
    operations = db.relationship('Operation',backref='user',lazy='dynamci')
    def __repr__(self):
        return '<User %r>'%self.phone

class Operation(db.Model):
	__tablename__='operation'
	id = db.Column(db.Integer, primary_key = True)
	action = db.Column(db.Integer)
	time = db.Column(db.DateTime)
	user_id = db.Column(db.Integer,db.ForeignKey('user.id'))

在Operation類中,對欄位新增ForeignKey的宣告,就可以將兩張表連線起來了;在User表中新增一個db.relationship的宣告,就可以直接連線user物件(而不僅僅是user_id)。

4.2 sqlite操作

在建立了ORM模型後,我們可以直接使用它進行sqlite的操作。
首先開啟python shell,執行下面的語句:

from schedule import db, User, Operation#這裡匯入放置ORM模型的py檔案
db.create_all() #根據config中宣告的地址建立資料庫,並根據ORM的類建立表。
user1 = User(phone = '15000000000',pw = '123456')
user2 = User(phone = '18900000000',pw = '654321')
oper1_1 = Operation(action = 1, time = '2018-11-12 12:23:30',user = user1)
oper1_2 = Operation(action = 2, time = '2018-11-12 15:13:20',user = user1)

通過資料庫的會話管理對資料庫進行操作

db.session.add_all([user1,user2,oper1_1,oper1_2])
db.session.commit()

增、改都使用add/add_all方法,刪除用delete方法,查詢用query方法,例如:

>>> User.query.all()
>>> User.query.filter_by(phone=form.username.data).first()
>>> user1.operations.filter_by(action = 1).count()

可以使用DDL語句直接在python中進行查詢。直接輸入sqlite3 + 資料庫檔案可以進入shell介面,使用SQL命令即可進行查詢:
在這裡插入圖片描述

.header on 顯示錶頭
.mode column 列顯示方式
.databases 顯示資料庫
.tables 顯示錶名