web開發之flask簡介
文章目錄
- 1. 基本概念
- 1.1 初始化
- 1.2 路由和檢視函式
- 1.3 上下文
- 1.4 響應和重定向
- 1.5 Flash訊息傳遞
- 2. 模板
- 2.1 渲染過程
- 2.2 控制結構
- 2.3 bootstrap
- 3. 表單
- 3.1 啟用CSRF保護
- 3.2 建立表單類
- 4. 資料庫
- 4.1 ORM模型
- 4.2 sqlite操作
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 顯示錶名