日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Flask Web 開發學習稿(二)

Flask Web 開發學習稿(二)

來源:程序員人生   發布時間:2016-06-29 17:03:34 閱讀次數:3184次

第4章 Web 表單

request.from 能獲得 POST 要求中提交的表單數據
Flask-WTF 擴大可以把處理 Web 表單的進程變成1種愉悅的體驗

4.1 跨站要求捏造保護

默許情況下,Flask-WTF 能保護所有表單免受跨站要求捏造的攻擊,為了實現 CSRF 保護,Flask-WTF 需要程序設置1個密鑰,會使用這個密鑰生成加密令牌,再用令牌驗證要求中表單數據的真偽
設置密鑰的方法如示例所示

app = Flask(__name__) app.config['SECRET_KEY'] = 'This is a secret key'

app.config字典可用來存儲框架、擴大和程序本身的配置變量,這個對象還提供了1些方法可以從文件或環境中導入配置值。SECRTET_KEY 配置變量是通用密鑰,可在 Flask 和多個第3方擴大中使用。

為了增強安全性,密鑰不應當直接寫入代碼,而要保存在環境變量中

4.2 表單類

使用 Flask-WTF 時,每一個 Web 表單都由1個繼承自 Form 的類表示,這個類定義表單中的1組字段,每一個字段都用對象表示,字段對象可附屬1個或多個驗證函數

from flask.ext.wtf import Form from wtforms import StringField, SubmitField from wtforms.validators import Required class NameForm(Form): name = StringField('What is your name?', validators=[Required()]) submit = SubmitField('Submit')

表單的每一個屬性都定義為類的屬性,類變量的值是相應字段類型的對象,StringField 類表示屬性為 type="text" 的 元素,SubmitField 類表示屬性為 type="submit" 的 元素
字段構造函數的第1個參數是把表單渲染成 HTML 時使用的標號,可選參數 validators 指定1個由驗證函數組成的列表,在接受用戶提交的數據之前驗證數據,驗證函數Required()確保提交的字段不為空

Form 基類由 Flask-WTF 擴大定義,所以從 flask.ext.wtf 中導入,字段和驗證函數卻可以直接從 WTForms 包中導入

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

WTForms 內建的驗證函數以下表所示

驗證函數 說明
Email 驗證電子郵件地址
EqualTo 比較兩個字段的值,經常使用于密碼確認
IPAddress 驗證IPv4網絡地址
Length 驗證輸入字符串的長度
NumberRange 驗證輸入的值在數字范圍內
Optional 無輸入值時跳過其他驗證函數
Required 確保字段中有數據
Regexp 使用正則表達式驗證輸入值
URL 驗證URL
AnyOf 確保輸入值在可選值列表中
NoneOf 確保輸入值不在可選值列表中

4.3 把表單渲染成HTML

index.html

{% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}Flasky{% endblock %} {% block page_content %} <div class="page-header"> <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1> </div> {{ wtf.quick_form(form) }} {% endblock %}

import 允許導入模版中的元素并用在多個模版中,導入的 bootstrap/wtf.html 文件中定義了1個使用 Bootstrap 渲染 Flask-WTF 表單對象的輔助函數。
wtf.quick_form() 函數的參數為 Flask-WTF 表單對象,使用 Bootstrap 的默許樣式渲染傳入的表單
該文件中使用了模版條件語句,在 Jinja2 中的條件語句格式為{% if condition %}...{% else %}...{% endif %},如果條件的計算結果為 True,那末渲染 if 和 else 指令之間的值,如果為 False,則渲染 else 和 endif 指令之間的值。此處,如果沒有模版變量 name 就渲染字符串 Stranger。
下面使用 wtf.quick_form() 函數渲染 NameForm 對象

4.4 在視圖函數中處理表單

這里寫圖片描述
在使用了 manager.run() 以后,啟動的方式有所變化,必須附加參數 runserver,如上圖所示

from flask import Flask, render_template from flask.ext.script import Manager from flask.ext.bootstrap import Bootstrap from flask.ext.moment import Moment from flask.ext.wtf import Form from wtforms import StringField, SubmitField from wtforms.validators import Required app = Flask(__name__) app.config['SECRET_KEY'] = 'hard to guess string' manager = Manager(app) bootstrap = Bootstrap(app) moment = Moment(app) class NameForm(Form): name = StringField('What is your name?', validators=[Required()]) submit = SubmitField('Submit') ![icone.png-22.2kB][1] @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 @app.route('/', methods=['GET', 'POST']) def index(): name = None form = NameForm() if form.validate_on_submit(): name = form.name.data form.name.data = '' return render_template('index.html', form=form, name=name) if __name__ == '__main__': manager.run()

index.html 沿用上1小節的便可,運行后可以得到以下頁面
這里寫圖片描述
methods 通知 Flask 在 URL 映照中把這個視圖函數注冊為 GET 和 POST 要求的處理程序,如果沒指定 methods 參數,只會注冊為 GET 要求的處理程序
在視圖函數中創建1個 NameForm 類實例用于表示表單,如果數據能被所有的驗證函數接受,那末form.validate_on_submit() 的返回值為 True,這個函數的返回值決定是重新渲染表單還是處理表單提交的數據
1個要求的詳解:**用戶提交表單后,1個 POST 要求過來,validate_on_submit() 會調用 name 字段上附屬的 Required() 驗證函數,如果名字不為空就可以通過驗證,函數返回 True。
用戶輸入的名字通過字段的 data 屬性獲得,在 if 語句中把名字賦值給局部變量 name,再把 data 屬性置為空字符串,從而清空表單字段**
如果提交表單時,沒有填入內容, Required 驗證函數會捕獲毛病并顯示提示,良好的擴大讓程序具有更加強大的功能

4.5 重定向和用戶會話

當我過1段時間后點擊了刷新按鈕時,閱讀器會彈出提示詢問我是不是想要重新提交表單,由于閱讀器發出的最后1個要求是 POST 要求。
使用重定向作為 POST 要求的響應,而不是使用常規響應可以規避這個問題,但是如此這般又引入了新問題。使用 form.name.data 獲得用戶輸入的名字,在要求結束時數據丟失。這里我們需要用到用戶會話,把數據存儲在用戶會話中,在要求之間記住數據

默許情況下,用戶會話保存在客戶端 Cookie 中,使用設置的 SECRET_KEY 進行加密簽名,如果篡改了 Cookie 中的內容,簽名就會失效,會話也就失效了

def index(): form = NameForm() if form.validate_on_submit(): session['name'] = form.name.data return redirect(url_for('index')) return render_template('index.html', form=form, name=session.get('name'))

修改其視圖函數就能夠完成功能,之前的名字被保存在局部變量中,現在保存在用戶會話里,在需要的時候可以取出使用
redirect() 是個輔助函數,用來生成 HTTP 重定向響應,重定向可以寫根地址也能夠使用 URL 生成函數 url_for(),推薦使用生成函數生成 URL,這樣保證了 URL 和定義的路由兼容,而且修改路由名字后仍然可用
url_for() 函數的唯逐一個必須指定的參數是端點名,即路由的內部名字,默許情況下,路由的端點是相應視圖函數的名字

4.6 Flash 消息

提示消息使用flash()函數實現

def index(): form = NameForm() if form.validate_on_submit(): old_name = session.get('name') if old_name is not None and old_name != form.name.data: flash('Looks like you have changed your name!') session['name'] = form.name.data return redirect(url_for('index')) return render_template('index.html', form=form, name=session.get('name'))

將視圖函數修改成上面這樣便可
僅調用flash()函數其實不能把消息顯示出來,程序使用的模版要渲染這些消息,最好在基模版中渲染 Flash 消息,這樣所有頁面都能使用這些消息, Flask 把get_flashed_messages()函數開放給模版,用來獲得并渲染消息,將base.html修改以下

{% extends "bootstrap/base.html" %} {% block title %}Flasky{% 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="/">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"> {% 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 %}

第5章 數據庫

5.1 NoSQL 數據庫

NoSQL 數據庫1般使用集合代替表,使用文檔代替記錄

5.2 Python 數據庫框架

  • 易用性
    數據庫抽象層,又被稱作object-relational mappers (ORMs) 或 object-document mappers (ODMs),提供了從高級對象到低級數據庫實體的直接轉換,使用起來固然會更加方便。

  • 性能
    ORMs和ODMs把對象轉化為數據庫實體會有1些開消,但多數時候這個開消可以疏忽不計的。通常來講,使用ORMs和ODMs帶來的工作效能提升常常大于所帶來的性能消耗,因此我們沒有甚么理由謝絕ORMs和ODMs。通常比較公道的做法是用數據庫抽象層來做經常使用的操作,而只在某些需要特別優化的地方使用原生的數據庫操作。

  • 可移植性
    所選擇的數據庫在生產和部署環境下是不是可用是1個必須斟酌的因素,比如你想要把你的利用部署在云平臺上,你固然應當首先知道該平臺支持哪些數據庫
    ORMs和ODMs還能帶來的其他1個便利。雖然多數數據庫提供了1個抽象層,但是還有1些更高階的抽象層提供了只用1套接口便可操作多種數據庫的功能。最好的例子就是SQLAlchemy ORM,它提供了1系列關系型數據庫引擎的支持,比如MySQL、Postgres 和 SQLite。

  • Flask 集成度
    雖然不是必須要求能和Flask集成,但是能和Flask集成意味著能為你省去你大量書寫代碼的時間 。正是由于使用Flask集成的數據庫引擎能簡化配置和操作,你應當盡量選擇Flask擴大情勢的數據庫引擎包。綜上,本書將會選擇Flask-SQLAlchemy作為數據庫工具,它是1個基于SQLAlchemy的Flask擴大。

本書選擇了 Flask-SQLAlchemy

5.3 使用 Flask-SQLAlchemy 管理數據庫

使用 pip install flask-sqlalchemy 來安裝 Flask-SQLAlchemy
Flask-SQLAlchemy 數據庫使用 URL 指定,流行的數據庫 URL 指定表以下

數據庫引擎 URL
MySQL mysql://username:password@hostname/database
Postgres postgresql://username:password@hostname/database
SQLite(Unix) sqlite:////absolute/path/to/database
SQLite(Windows) sqlite:///c:/absolute/path/to/database

hostname 是數據庫服務所在的主機,database 指定使用的數據庫名,username 和 password 表示數據庫密令

SQLite 數據庫不需要使用服務器,只需要指定硬盤上的文件便可

程序使用的數據庫 URL 被在配置在 Flask 的 config 對象的 SQLALCHEMY_DATABASE_URI 中,還有另外一個重要的屬性被配置在 SQLALCHEMY_COMMIT_ON_TEARDOWN 中用來在每次要求結束時候自動提交數據庫改動,Flask-SQLAlchemy 官方文檔提供了更多配置選項。以下是1個配置 SQLite 數據庫的例子:

from flask.ext.sqlalchemy import SQLAlchemy basedir = os.path.abspath(os.path.dirname(__file__)) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = \ 'sqlite:///C:\\Users\\Avenger\\Desktop\\test\\database.db' app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app)

千萬設置好['SQLALCHEMY_DATABASE_URI']這1行,否則會報錯,注意 Windows 下是3個/
模型是指那些在程序中被持久化的對象,在 ORM 的環境下,1個模型是1個典型的 Python 類,類中的屬性對應數據庫表中的列。
Flask-SQLAlchemy 數據庫的實例提供了1個 model 的基類和1系列的工具方法方法來定義他們的結構,在前面示例中的 roles 和 users 表可以定義成以下的 Role 和 User models

class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) def __repr__(self): return '<Role %r>' % self.name class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) def __repr__(self): return '<User %r>' % self.username

類變量 __tablename__ 定義在數據庫中使用的表名,如果沒有定義 __tablename__ 會被指定1個默許的名字,推薦自己來命名。其余的類變量都是該模型的屬性,被定義為 db.Column
db.Column 類構造函數的第1個參數是數據庫列和模型屬性的類型,其余的參數指定屬性的配置選項,以下表所示
這兩個模型都定義了 __repr()__ 方法,返回1個具有可讀性的字符串表示模型,可在調試時使用
最經常使用的列類型

類型名 Python 類型 說明
Integer int 普通整數,1般是32位
SmallInteger int 取值范圍小的整數,1般是16位
BigInteger int or long 不限制精度的整數
Float float 浮點數
Numeric decimal.Decimal 定點數
String str 變長字符串
Text str 變長字符串,對較長或不限長度的字符串做了優化
Unicode unicode 變長 Unicode 字符串
UnicodeText unicode 變長 Unicode 字符串,對較長或不限長度的字符串做了優化
Boolean bool 布爾值
Date datetime.date 日期
Time datetime.time 時間
DateTime datetime.datetime 日期和時間
Interval datetime.timedelta 時間間隔
Enum str 1組字符串
PickleType Any Python object 自動使用 Pickle 序列化
LargeBinary str 2進制文件

最經常使用的列選項

選項名 說明
primary_key 如果設為 True,這列就是表的主鍵
unique 如果設為 True,這列不允許出現重復值
index 如果設為 True,為這列創建索引,提升查詢效力
nullable 如果設為 True,這列允許使用空值,如果設為 False,這列不允許使用空值
default 為這列設定默許值

Flask-SQLAlchemy 要求每一個模型都要定義主鍵,這1列常常命名為 id

5.4 關系

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 class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) def __repr__(self): return '<User %r>' % self.username

關系使用 users 屬性代表這個關系的面向對象視角,對1個 Role 類的實例,其 users 屬性將返回
"users = db.relationship('User', backref='role')" 代表這個關系的面向對象的視圖。能返回指定角色的相干人員列表。當外鍵由多個組成時,還需要斟酌1些其他參數:

選項名 說明
backref 在關系的另外一個模型中添加反向援用
primaryjoin 明確指定兩個模型之間使用的聯結條件,只在模棱兩可的關系中需要指定
lazy 指定如何加載相干記錄,詳細見附表
uselist 如果設為 False 不使用列表,而使用標量值
order_by 指定關系中記錄的排序方式
secondary 指定多對多關系中關系表的名字
secondaryjoin SQLAlchemy 沒法自行決定時,指定多對多關系中的2級聯結條件

附表

可選值 說明
select 首次訪問時按需加載
immediate 源對象加載后就加載
joined 加載記錄,使用聯結
subquery 立即加載,使用子查詢
noload 永不加載
dynamic 不加載記錄,但提供加載記錄的查詢

5.5 數據庫操作

5.5.1 創建表 & 插入行

if __name__ == '__main__': db.create_all() admin_role = Role(name='Admin') mod_role = Role(name='Moderator') user_role = Role(name='User') user_john = User(username='john', role=admin_role) user_susan = User(username='susan', role=user_role) user_david = User(username='david', role=user_role) manager.run()

db.create_all()用來創建數據庫,以后的語句都是插入行(在 Role 表和 users 表中)
我們在 SQLiteStudio 來連接這個數據庫看是不是創建成功
這里寫圖片描述

可以發現這個表和列都已創建OK了,但是此時這些對象其實不是真實的數據庫內容,只在 Python 中,還未寫入數據庫,因此 id 等都還沒有賦值

db.session.add(admin_role) db.session.add(mod_role) db.session.commit()

可使用這類方法來寫入數據庫commit() 之前都是將對象添加到會話中,commit() 來提交這個會話就能夠寫入數據庫了。添加對象到會話時,我們可簡寫為以下

db.session.add_all([admin_role, mod_role, user_role,user_john, user_susan, user_david]) db.session.commit()

這里寫圖片描述
可以直接看出,相干數據已寫入了數據庫

使用把相干改動放在會話中提交,在寫入會話時產生毛病,全部會話都會失效,這樣可以免由于部份更新而致使數據庫不1致
數據庫會話也能夠回滾,db.session.rollback() 可以把添加到數據庫會話中的所有對象都還原到初始狀態

5.5.2 修轉業 & 刪除行

數據庫會話中調用 add() 方法也能更新模型,使用 delete() 可以刪除

if __name__ == '__main__': db.create_all() admin_role = Role(name='Admin') mod_role = Role(name='Moderator') user_role = Role(name='User') user_john = User(username='john', role=admin_role) user_susan = User(username='susan', role=user_role) user_david = User(username='david', role=user_role) db.session.add_all([admin_role, mod_role, user_role, user_john, user_susan, user_david]) db.session.commit() admin_role.name = 'Administrator' db.session.add(admin_role) db.session.delete(mod_role) db.session.commit() manager.run()

在原有項目上測試,會遇到問題,不能重新更新原來的值,重新創建1個空文件連接數據庫寫入就行了,簡單粗魯的辦法
這里寫圖片描述
可以看出,更新和刪除操作都已可以履行了!插入、刪除、更新都必須提交數據庫會話才能履行。

5.5.3 查詢行

Role.query.all() User.query.all() User.query.filter_by(role=user_role).all() str(User.query.filter_by(role=user_role)) user_role = Role.query.filter_by(role=user_role)

每一個模型都有 query 對象,使用過濾器可以配置 query 對象進行更精確的數據庫查詢,第3個就是查詢角色為“user”的所有用戶,第4條是查看SQLAlchemy為查詢生成的原生 SQL 語句
user_role = Role.query.filter_by(name='User').first() 可以查詢名為 User 的用戶角色。多個過濾器可以1起調用來獲得所需結果
經常使用過濾器:

過濾器 說明
filer() 把過濾器添加到原查詢上,返回1個新查詢
filter_by() 把等值過濾器添加到原查詢上,返回1個新查詢
limit() 使用指定的值限制原查詢結果返回的結果數量,返回1個新查詢
offset() 偏移原查詢返回的結果,返回1個新查詢
order_by() 根據指定條件對原查詢結果進行排序,返回1個新查詢
group_by() 根據指定條件對原查詢結果進行分組,返回1個新查詢

在查詢上利用了過濾器后,通過調用all()履行查詢,以列表的情勢返回結果,全部查詢方法以下

過濾器 說明
all() 以列表情勢返回查詢的所有結果
first() 返回查詢的第1個結果,如果沒有結果,返回 None
first_or_404() 返回查詢的第1個結果,如果沒有結果,終止要求,返回 404 響應毛病
get() 返回指定主鍵對應的行,如果沒有對應的行,返回 None
get_or_404() 返回指定主鍵對應的行,如果沒有指定的主鍵,終止要求,返回 404 響應毛病
count() 返回查詢結果的數量
paginate() 返回1個 Paginate 對象,它包括指定范圍內的結果

下面這個例子分別從關系的兩端查詢角色和用戶之間的1對多關系

users = user_role.users 在履行 user_role.users 時,隱含的查詢會調用 all() 返回1個用戶列表, query 對象是隱藏的,因此沒法指定更精確的查詢過濾器,改進以下

我們可以通過修改關系的設置,加入lazy = 'dynamic' 參數,從而制止自動履行查詢

class Role(db.Model) #... users = db.relationship('User', backref='role', lazy='dynamic') #...

這樣配置關系后,users = user_role.users 會返回1個還沒有履行的查詢,因此可以在其上添加過濾器了

user_role.users.order_by(User.username).all() user_role.users.count()

5.6 在視圖函數中操作數據庫

修改視圖函數以下

@app.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) session['known'] = False else: # 存在的用戶,在網站會話中給出已知,用于在 index.html 中進行判斷 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))

在啟動這個 app 之前,需要初始化這個數據庫嘛,在 manager.run() 之前,

if __name__ == '__main__': db.create_all() admin_role = Role(name='Admin') mod_role = Role(name='Moderator') user_role = Role(name='User') user_john = User(username='john', role=admin_role) user_susan = User(username='susan', role=user_role) user_david = User(username='david', role=user_role) db.session.add_all([admin_role, mod_role, user_role, user_john, user_susan, user_david]) db.session.commit() admin_role.name = 'Administrator' db.session.add(admin_role) db.session.delete(mod_role) db.session.commit() print(Role.query.all()) print(User.query.all()) print(User.query.filter_by(role=user_role).all()) print(str(User.query.filter_by(role=user_role))) print(user_role.users.order_by(User.username).all()) manager.run()

index.html 也需要修改,以下

{% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}Flasky{% endblock %} {% block page_content %} <div class="page-header"> <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1> {% if not known %} <p>Pleased to meet you!</p> {% else %} <p>Happy to see you again!</p> {% endif %} </div> {{ wtf.quick_form(form) }} {% endblock %}

運行以后,在首頁提交表單,可以看到提交的名字成功被插入到了數據庫
這里寫圖片描述
再次提交這個名字的話,就會看到Happy to see you again!的歡迎提示

5.7 集成 Python Shell

from flask.ext.script import Manager, Shelldef make_shell_context(): return dict(app=app, db=db, User=User, Role=Role)manager.add_command("shell", Shell(make_context=make_shell_context))

在 Python 腳本中,增加上述語句,可讓 Flask-Script 的 shell 命令自動導入特定的對象,若想把對象添加到導入列表中,我們要為 shell 命令注冊1個 make_context 回調函數
make_shell_context() 函數注冊了程序、數據庫實例和模型,因此這些對象能直接導入 shell
履行 python hello.py shell 就引入了這些對象

5.8 使用 Flask-Migrate 進行數據遷移

更新表的唯1方法就是刪除舊表 db.drop_all()
更新表的更好辦法是使用數據庫遷移框架, SQLAlchemy 的研發了1個叫做 Alembic,也能夠使用 Flask-Migrate 擴大,這個擴大輕量級包裝了 Alembic

5.8.1 創建遷移倉庫

首先進行安裝 pip install flask-migrate
再進行初始化:
導入:from flask.ext.migrate import Migrate, MigrateCommand
初始化:

migrate = Migrate(app, db) manager.add_command('db', MigrateCommand)

為了導出數據庫遷移指令,Flask-Migrate 提供了1個 MigrateCommand 類,可附加到 Flask-Script 的 manager 對象中
這里寫圖片描述
修改腳本參數如上如所示,運行可得
這里寫圖片描述
在腳本的目錄下創建了 migrations 文件夾,所有遷移腳本都寄存在其中

數據庫遷移倉庫中的文件要和程序的其他文件1起納入版本控制

5.8.2 創建遷移腳本

在 Alembic 中,數據庫遷移用遷移腳本表示。腳本中有兩個函數,分別是 upgrade()downgrade()。 upgrade() 函數把遷移中的改動利用到數據庫中, downgrade() 函數則將改動刪除。 Alembic 具有添加和刪除改動的能力,因此數據庫可重設到修改歷史的任意1點。
我們可使用 revision 命令手動創建 Alembic 遷移,也可以使用 migrate 命令自動創建。手動創建的遷移只是1個骨架, upgrade()downgrade() 函數都是空的,開發者要使用Alembic 提供的 Operations 對象指令實現具體操作。自動創建的遷移會根據模型定義和數據庫當前狀態之間的差異生成 upgrade()downgrade() 函數的內容。

自動創建的遷移不1定總是正確的,自動生成遷移腳本后1定要進行檢查

python hello.py db migrate -m "initial migration" 自動創建遷移腳本的 migrate 命令

5.8.3 更新數據庫

檢查并修正好遷移腳本后,我們可使用 db upgrade 命令把遷移利用到數據庫
第1個遷移的作用和調用 db.create_all() 方法1樣,但在后面的遷移中 upgrade 可以把改動利用到數據庫中,且不影響其中保存的數據
書中說數據庫的名字是 data.sqlite 但是我沒有成功,我的數據庫的名字是 database.db 應當沒有區分,只是提起

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 日本黄色成人 | 久久精品99国产精品 | 91欧美精品成人综合在线观看 | 亚洲一二三在线 | 黄色一级片在线 | 麻豆国产尤物av尤物在线观看 | 三级av免费看 | 男人的天堂avav | 黄色福利视频 | 国产高清在线观看 | 欧美91| 精品一区视频 | 欧美日一 | 精品久久久久久久久久久aⅴ | zzzwww在线看片免费 | 国产精品视频1区 | 成人欧美一区二区三区视频xxx | 日韩欧美一区二区三区在线视频 | 国产日韩欧美在线 | 国产精品视频不卡 | 欧美一区二区三区视频 | 99视频在线| 久久大陆 | 污网站在线观看 | 欧美五月| 成人欧美一区二区三区黑人动态图 | 欧美精品xxx | 色性视频 | 亚洲国产精品网站 | 亚洲青青草| 黄色一级片在线 | 精品一级毛片 | 日日网 | av久久久 | xxx69在线观看 | 国产成人av一区二区三区 | 欧美亚洲免费 | 九九热在线观看 | 亚洲精品国产精品国自产观看浪潮 | www.射| 亚洲视频一 |