1. 需要安裝的包
- pip install flask
- pip install flask_script
- pip install flask_bootstrap
- pip install flask_moment
- pip install flask_wtf
- pip install flask_sqlalchemy
- pip install flask_mail
- pip install flask_login
- pip install pymysql
- pip install flask_migrate
- pip install hashlib
- pip install faker #生成虛擬數(shù)據(jù)的
- pip install flask_pagedown
- pip install markdown
- pip install bleach
- pip install flask_httpauth
- pip install httpie
- pip install selenium
2. bootstrap
3. 響應(yīng)abort函數(shù)
一種特殊的響應(yīng)由abort函數(shù)生成琴昆,用于處理錯(cuò)誤
4. @app.errorhandler
用來(lái)處理狀態(tài)碼錯(cuò)誤的
@app.errorhandler(400)
def page_not_found(e):
return render_template('404.html'),404
5.{% import "bootstrap/wtf.html" as wtf %}
在模板中使用{% import "bootstrap/wtf.html" as wtf %}
.
import
指令的使用方法和普通Python
代碼一樣漓滔,允許導(dǎo)入模板中的元素并用在多個(gè)模板中癌刽。
6. 數(shù)據(jù)庫(kù)
(1).
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
users = db.relationship('User', backref='role')
def __repr__(self):
return '<Role %r>' % self.name
Flask-SQLAlchemy創(chuàng)建的數(shù)據(jù)庫(kù)實(shí)例為模型提供了一個(gè)基類以及一系列輔助類和輔助函數(shù)毫目,可用于定義模型結(jié)構(gòu)复颈。
類變量__tablename__
定義在數(shù)據(jù)庫(kù)中使用的表名逾一。如果沒有定義__tablename__
,Flask-SQLAlchemy會(huì)使用一個(gè)默認(rèn)名字分飞,但默認(rèn)的表名沒有遵守使用復(fù)數(shù)形式進(jìn)行命名的約定婿失。其余的類變量都是該模型的屬性嫩痰,被定義db.Column
類的實(shí)例剿吻。
(2).要讓Flask-SQLAlchemy根據(jù)模型類創(chuàng)建數(shù)據(jù)庫(kù)。方法是使用db.create_all()
函數(shù)串纺。如果數(shù)據(jù)庫(kù)表已經(jīng)存在與數(shù)據(jù)中丽旅,那么db.create_all()不會(huì)重新創(chuàng)建或者更新這個(gè)表椰棘。如果修改模型后要把改動(dòng)應(yīng)用到現(xiàn)有的數(shù)據(jù)庫(kù)中,這一特性會(huì)帶來(lái)不便榄笙。更新現(xiàn)有的數(shù)據(jù)庫(kù)表的粗暴方式是先刪除舊表再重新創(chuàng)建:
>>>db.drop_all()
>>>db.create_all()
數(shù)據(jù)庫(kù)的操作是先創(chuàng)建模型的實(shí)例邪狞,然后將數(shù)據(jù)加入到數(shù)據(jù)庫(kù)會(huì)話中db.session
。要將對(duì)象寫入數(shù)據(jù)庫(kù)茅撞,最后要使用db.commit()
提交會(huì)話帆卓。
數(shù)據(jù)庫(kù)會(huì)話db.session
和Flask session對(duì)象沒有關(guān)系。數(shù)據(jù)庫(kù)會(huì)話也稱為事務(wù)米丘。
數(shù)據(jù)庫(kù)會(huì)話可以回滾剑令,調(diào)用db.session.rollback()
后,添加到數(shù)據(jù)庫(kù)會(huì)話中的所有對(duì)象都會(huì)還原到它們?cè)跀?shù)據(jù)庫(kù)時(shí)的狀態(tài)拄查。
(3). python hello.py shell
使用與運(yùn)行
要想使用python hello.py shell
但沒有沒有進(jìn)入 shell 環(huán)境吁津。原因?yàn)闆]有調(diào)用manager.run()
,應(yīng)該要使用如下代碼,才能進(jìn)入shell環(huán)境。
from flask_script import Manager
if __name__ == '__main__':
manager.run()
(4).數(shù)據(jù)庫(kù)插入行admin_role = Role(name = 'Admin')
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64),unique = True)
users = db.relationship('User',backref='role')
def __repr__(self):
return '<Role %r>'%self.name
admin_role = Role(name = 'Admin')
模型的構(gòu)造函數(shù)接受的參數(shù)是使用關(guān)鍵字參數(shù)指定的模型屬性初始值堕扶。
7. 使用Flask_mail
發(fā)送電子郵件
from flask_mail import Mail, Message
app.config['MAIL_SERVER'] = 'smtp.126.com'
app.config['MAIL_PORT'] = 25
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = 'MAIL_USERNAME'
app.config['MAIL_PASSWORD'] = 'MAIL_PASSWORD'
成功用上述代碼在python shell中發(fā)送郵件
8. WTForm表單的field的取值form.name.data
9.藍(lán)本Blueprint
的使用
(1)創(chuàng)建藍(lán)本
# app/main/__init__.py
from flask import Blueprint
main = Blueprint('main',__name__)
from . import views,errors
錯(cuò)誤與路由處理的程序在app/main/init.py腳本的末尾導(dǎo)入碍脏,這是為了避免循環(huán)導(dǎo)入依賴,因?yàn)樵趘iews.py和errors.py中還要導(dǎo)入藍(lán)本main稍算。
--Python是腳本語(yǔ)言典尾,只會(huì)由上往下執(zhí)行
(2)藍(lán)本中的錯(cuò)誤處理程序
from flask import render_template
from .import main
@main.app_errorhandler(404)
def page_not_found(e):
return render_template('404.html'),404
@main.app_errorhandler(500)
def internal_server_error(e):
return render_template('500.html'),500
只有藍(lán)本中的錯(cuò)誤才能觸發(fā)處理程序,要想注冊(cè)程序全局的錯(cuò)誤處理程序糊探,必須使用app_errorhandler
(3)藍(lán)本中定義路由
from flask import render_template, session, redirect, url_for, current_app
from .. import db
from ..models import User
from ..email import send_email
from . import main
from .forms import NameForm
@main.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.name.data).first()
if user is None:
user = User(username=form.name.data)
db.session.add(user)
db.session.commit()
session['known'] = False
if current_app.config['FLASKY_ADMIN']:
send_email(current_app.config['FLASKY_ADMIN'], 'New User',
'mail/new_user', user=user)
else:
session['known'] = True
session['name'] = form.name.data
return redirect(url_for('.index'))
return render_template('index.html',
form=form, name=session.get('name'),
known=session.get('known', False))
藍(lán)本中編寫的視圖函數(shù)主要有兩點(diǎn)不同:
- 1 路由修飾器是由藍(lán)本提供的
- 2 url_for()函數(shù)的用法不同钾埂。url_for()函數(shù)的第一個(gè)參數(shù)是路由的端點(diǎn)名,在程序的路由中侧到,默認(rèn)為視圖函數(shù)的名字勃教。例如,在單腳本程序中匠抗,index()視圖函數(shù)的URL可使用url_for('index')獲取
而在藍(lán)本中就不一樣故源,F(xiàn)lask會(huì)為藍(lán)本中的全部端點(diǎn)加上一個(gè)命名空間,這樣就可以在不同的藍(lán)本中使用相同的端點(diǎn)名定義視圖函數(shù)汞贸,而不會(huì)產(chǎn)生沖突绳军。命名空間就是藍(lán)本的名字(Blueprint構(gòu)造函數(shù)的第一個(gè)參數(shù)),所以視圖函數(shù)index()注冊(cè)的端點(diǎn)名是main.index,其URL使用`url_for('main.index')獲得
9. 認(rèn)證藍(lán)本
render_template()
指定的模板文件保存在auth
文件夾中矢腻,這個(gè)文件夾必須在app/templates
中創(chuàng)建门驾,因?yàn)镕lask認(rèn)為模板的路徑是相對(duì)魚程序模板文件夾而言的。render_template()
函數(shù)會(huì)首先搜索程序配置的模板文件夾多柑,然后在搜索藍(lán)本的配置的模板文件夾
10. 數(shù)據(jù)庫(kù)migrations時(shí)遭遇錯(cuò)誤(Can't locate revision identified by ‘xxx’)
這種錯(cuò)誤最簡(jiǎn)單的解決辦法就是把數(shù)據(jù)庫(kù)中的alembic_version表刪掉奶是,然后就可以繼續(xù)后面的操作了
11.添加登錄表單
登錄頁(yè)面使用的模板保存在auth/login.html文件中。這個(gè)模板只需要是使用Flask-Bootstrap
提供的wtf.quick_form()宏渲染表單即可。
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky - Login{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Login</h1>
</div>
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
12.保護(hù)路由
Flask-login提供了一個(gè)login_required修飾器聂沙。
from flask_login import login_required
@app.route('/secret')
@login_required
def secret():
return 'Only authenticated users are allowed!'
13.表單類
- 表單的創(chuàng)建秆麸,可以通過(guò)繼承從 Flask-WTF 導(dǎo)入的
FlaskForm
父類實(shí)現(xiàn)
from flask_wtf import FlaskForm # 表單類,從第三方擴(kuò)展的命名空間 導(dǎo)入
- 表單類中需要定義 屬性/字段及汉,值是字段類型類沮趣,就是將要在 HTML 中顯示的表單各個(gè)字段,其實(shí)就是對(duì) HTML 表單各種標(biāo)簽的包裝
from wtforms import StringField,PasswordField,BooleanField,SubmitField
- 字段類型類(說(shuō)明文本坷随,驗(yàn)證器列表)
驗(yàn)證器列表房铭,檢查用戶填寫表單時(shí)輸入的內(nèi)容是否符合我們的期望,有多個(gè)驗(yàn)證器時(shí)温眉,需要同時(shí)通過(guò)驗(yàn)證
from wtforms.validators import DataRequired,Length,Email,Regexp,EqualTo
# 普通用戶的資料編輯表單
class EditProfileForm(Form):
name = StringField('Real name', validators=[Length(0, 64)]) # 因?yàn)槭强蛇x缸匪,允許長(zhǎng)度為0
location = StringField('Location', validators=[Length(0, 64)])
about_me = TextAreaField('About me') # 文本區(qū)域,可以多行芍殖,可以拉動(dòng)
submit = SubmitField('Submit')
在表單類中定義了以validate_開頭并且后面跟著字段名的方法豪嗽,這個(gè)方法就和常規(guī)的驗(yàn)證函數(shù)一起調(diào)用谴蔑。自定義的驗(yàn)證函數(shù)要想表示驗(yàn)證失敗豌骏,可以拋出ValidationError異常,其參數(shù)就是錯(cuò)誤信息隐锭。
class RegistrationForm(FlaskForm):
email = StringField('Email',validators=[DataRequired(),Length(1,64),Email()])
username = StringField('Username',validators=[DataRequired(),Length(1,64),Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0,
'Usernames must have only letters, numbers, dots or '
'underscores')])
password = PasswordField('Password',validators=[DataRequired(),EqualTo('password2',message='Passwords must match.')])
password2 = PasswordField('Confirm password',validators=[DataRequired()])
submit=SubmitField('Register')
def validate_email(self,field):
if User.query.filter_by(email = field.data).first():
raise ValidationError('Email already registered.')
def validate_username(self,field):
if User.query.filter_by(username = field.data).first():
raise ValidationError('Username already in use.')
14.沒有繼承的類class
class Permission:
FOLLOW = 1
COMMENT = 2
WRITE = 4
MODERATE = 8
ADMIN = 16
在寫Flask的用戶權(quán)限中看到上述的類定義窃躲。在Python中定義類class的時(shí)候,加上()
與不加上()
有沒有區(qū)別钦睡?
Python創(chuàng)建類的時(shí)候蒂窒,加()和不加有什么區(qū)別、聯(lián)系荞怒?
python的class(類)中繼承object 與不繼承的區(qū)別
通過(guò)查看上述的文章洒琢,可以得知的是事實(shí)上是沒有區(qū)別的,以下三種寫法是等價(jià)的
class A:
pass
class A():
pass
class A(object):
pass
15.類的方法
方法 init()
類中的函數(shù)稱為方法;你前面學(xué)到的有關(guān)函數(shù)的一切都適用于方法,就目前而言,唯一重要
的差別是調(diào)用方法的方式褐桌。 ?處的方法 init() 是一個(gè)特殊的方法,每當(dāng)你根據(jù) Dog 類創(chuàng)建新實(shí)
例時(shí),Python都會(huì)自動(dòng)運(yùn)行它衰抑。在這個(gè)方法的名稱中,開頭和末尾各有兩個(gè)下劃線,這是一種約
定,旨在避免Python默認(rèn)方法與普通方法發(fā)生名稱沖突。
16.Jinja2 宏方法
https://blog.csdn.net/hello_albee/article/details/51638358/
https://blog.csdn.net/whtqsq/article/details/76278374
17. 用戶資料編輯器(Edit Profile)
@main.route('/edit-profile',methods=['GET','POST'])
@login_required
def edit_profile():
form = EditProfileForm()
if form.validate_on_submit():
current_user.name = form.name.data
current_user.location = form.location.data
current_user.about_me = form.about_me.data
db.session.add(current_user._get_current_object())
db.session.commit()
flash('Your profile has been updated.')
return redirect(url_for('.user',username = current_user.username))
form.name.data = current_user.name
form.location.data = current_user.location
form.about_me.data = current_user.about_me
return render_template('edit_profile.html',form = form)
剛寫代碼的時(shí)候一直不是太懂為什么在顯示表單之前荧嵌,這個(gè)視圖函數(shù)要為所有字段設(shè)定了初始值呛踊。后來(lái)運(yùn)行了代碼,在網(wǎng)頁(yè)界面嘗試修改用戶profile才明白啦撮,初始值就是讓你在修改前谭网,能夠看到以前的用戶信息。
Edit Profile
在這里還有一個(gè)問(wèn)題赃春,當(dāng)用戶第一次訪問(wèn)程序時(shí)愉择,服務(wù)器會(huì)收到一個(gè)沒有表單數(shù)據(jù)的GET請(qǐng)求,所以validate_on_submit()將返回False。if語(yǔ)句的內(nèi)容將被跳過(guò)锥涕,通過(guò)渲染模板處理請(qǐng)求要拂!
當(dāng)用戶提交表單后,服務(wù)器收到一個(gè)包含數(shù)據(jù)的POST請(qǐng)求站楚。通過(guò)所有驗(yàn)證之后脱惰,validate_on_submit()返回True,然后執(zhí)行后續(xù)表單的數(shù)據(jù)的處理窿春。這里當(dāng)時(shí)自己有一個(gè)問(wèn)題拉一,就是執(zhí)行完return redirect(url_for('.user',username = current_user.username))
之后,后面的form.<field>.name數(shù)據(jù)還會(huì)不會(huì)執(zhí)行賦值旧乞?是不會(huì)的蔚润,因?yàn)槊恳粋€(gè)函數(shù)只會(huì)執(zhí)行返回一個(gè)值。當(dāng)執(zhí)行到return
語(yǔ)句并返回了值尺栖,就會(huì)跳出函數(shù)嫡纠。所以后續(xù)的語(yǔ)句是不會(huì)再執(zhí)行了。
18. Flask 'endpoint'端點(diǎn)的理解
Flask中'endpoint'(端點(diǎn))的理解1
Flask中endpoint的理解2
回到flask接受用戶請(qǐng)求地址并查詢函數(shù)的問(wèn)題延赌。實(shí)際上除盏,當(dāng)請(qǐng)求傳來(lái)一個(gè)url
的時(shí)候,會(huì)先通過(guò)rule找到endpoint
(url_map)挫以,然后再根據(jù)endpoint
再找到對(duì)應(yīng)的view_func
(view_functions)者蠕。通常,endpoint
的名字都和視圖函數(shù)名一樣掐松。
這時(shí)候踱侣,這個(gè)endpoint
也就好理解了:
實(shí)際上這個(gè)endpoint就是一個(gè)Identifier,每個(gè)視圖函數(shù)都有一個(gè)endpoint大磺,
當(dāng)有請(qǐng)求來(lái)到的時(shí)候抡句,用它來(lái)知道到底使用哪一個(gè)視圖函數(shù)
19. Flask Request
flask框架的請(qǐng)求上下文request中的args獲取請(qǐng)求參數(shù)方式
request.form 和request.args.get的區(qū)別
用url_for()來(lái)給指定的函數(shù)構(gòu)造URL。它接受函數(shù)名作為第一個(gè)參數(shù)杠愧,也接受對(duì)應(yīng)URL規(guī)則的變量部分的命名參數(shù)待榔。未知變量部分會(huì)添加到URL末尾作為查詢參數(shù)。
20.Flask中flash不顯示問(wèn)題
flask中有個(gè)flash功能用來(lái)提示用戶一些信息殴蹄,比如用戶退出登陸或者登陸用戶名密碼不匹配等究抓。。袭灯。
在開發(fā)過(guò)程中刺下,后臺(tái)里邊寫入消息提示flash,但是觸發(fā)了flash條件但是頁(yè)面并沒有顯示需要提示的信息稽荧。
原因:flash消息需要在模板中進(jìn)行渲染橘茉。
例子:用方法get_flashed_messages()來(lái)獲取后臺(tái)堆積的flash消息工腋,然后用一個(gè)for循環(huán)來(lái)顯示需要提示的信息。
應(yīng)用代碼:
@auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user is not None and user.verify_password(form.password.data):
login_user(user, form.remember_me.data)
return redirect(request.args.get('next') or url_for('main.index'))
flash('無(wú)效用戶名或密碼.')
return render_template('auth/login.html', form=form)
模板渲染:
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ message }}
</div>
{% endfor %}
{% block page_content %}{% endblock %}
</div>
21. Flask_script
flask_script的作用是可以通過(guò)命令行的形式來(lái)操作flask例如通過(guò)一個(gè)命令跑一個(gè)開發(fā)版本的服務(wù)器畅卓,設(shè)置數(shù)據(jù)庫(kù)擅腰,定時(shí)任務(wù)等.安裝flask_script比較簡(jiǎn)單,直接通過(guò)pip install flask_script安裝就可以了翁潘。
具體可以參考下面有關(guān)Flask_script的使用方法:
Flask之flask-script模塊使用
然后就是
從Flask-Script遷移到Flask-Cli
Flask 中的click模塊與Flask中的Flask_cli不知道是不是一樣的
還有遇到上面的這個(gè)錯(cuò)誤:
Error: Could not locate Flask application. You did not provide the FLASK_APP environment variable.
參考如何的文檔:
indows下Flask run報(bào)錯(cuò)'Could not locate flask application' 原因?
https://blog.csdn.net/AuserBB/article/details/79524470
像這樣設(shè)置環(huán)境變量:
(venv) $ export FLASK_APP=manage.py
windows就比較坑爹了趁冈,官方文檔中說(shuō)這么寫:
(venv) $ set FLASK_APP=manage.py
但是實(shí)際也許不會(huì)成功,會(huì)提示以下錯(cuò)誤:
Usage: flask run [OPTIONS]
Error: Could not locate Flask application. You did not provide the FLASK_APP environment variable.
For more information see http://flask.pocoo.org/docs/latest/quickstart/
我用的是PowerShell拜马,網(wǎng)上找了一些方法渗勘,都不成功,后來(lái)按照Stack Overflow上這個(gè)方法來(lái)就成功了:
(venv) $env:FLASK_APP = "manage.py"
Click模塊
Flask_cli是Click模塊的一個(gè)backport(補(bǔ)丁)
Flask-CLI is a backport of Flask 1.0 new click integration to v0.10.
Do not install this package if you use Flask 1.0+.
shell_context_processor
這個(gè)的作用是避免了每次啟動(dòng)shell會(huì)話時(shí)都要導(dǎo)入數(shù)據(jù)庫(kù)和模型
使用Flask的內(nèi)置click命令行啟動(dòng)Flask時(shí)總提示找不到'flask_bootstrap'
參考一下的解決方法
https://segmentfault.com/q/1010000015568164/a-1020000015595092