Flask數據庫操做

Python 數據庫框架

大多數的數據庫引擎都有對應的 Python 包,包括開源包和商業包。Flask 並不限制你使用何種類型的數據庫包,所以能夠根據本身的喜愛選擇使用 MySQL、Postgres、SQLite、Redis、MongoDB 或者 CouchDB。html

若是這些都沒法知足需求,還有一些數據庫抽象層代碼包供選擇,例如SQLAlchemyMongoEngine。你可使用這些抽象包直接處理高等級的 Python 對象,而不用處理如表、文檔或查詢語言此類的數據庫實體。python

選擇數據庫框架的因素:mysql

  • 易用性。抽象層,也稱爲對象關係映 射(Object-Relational Mapper,ORM) 或 對 象 文 檔 映 射(Object-Document Mapper,ODM),在用戶不知覺的狀況下把高層的面向對象操做轉換成低層的數據庫指令。
  • 性能。ORM 和 ODM 把對象業務轉換成數據庫業務會有必定的損耗。真正的關鍵點在於如何選擇一個能直接操做低層數據庫的抽象層,以防特定的操做須要直接使用數據庫原生指令優化。
  • 可移植性。必須考慮其是否能在你的開發平臺和生產平臺中使用。
  • Flask集成度

Flask-SQLAIchemy管理數據庫

  • 安裝
pip install flask-sqlalchemy
  • 1

使用URL制定數據庫sql

數據庫引擎 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

SQLite 數 據 庫 不 需 要 使 用 服 務 器, 因 此 不 用 指 定 hostname 、 username 和 password 。URL 中的 database 是硬盤上文件的文件名。shell

  • 配置 
    程序使用的數據庫 URL 必須保存到 Flask 配置對象的 SQLALCHEMY_DATABASE_URI 鍵中

配置對象中還有一個頗有用的選項,即 SQLALCHEMY_COMMIT_ON_TEARDOWN 鍵,將其設爲 True時,每次請求結束後都會自動提交數據庫中的變更數據庫

from flask.ext.sqlalchemy import SQLAlchemy basedir = os.path.abspath(os.path.dirname(__file__)) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] =\ 'sqlite:///' + os.path.join(basedir, 'data.sqlite') app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 定義模型
class Role(db.Model): __tablename__ = 'roles'#__tablename__ 定義在數據庫中使用的表名 id = db.Column(db.Integer, primary_key=True)#primary_key若是設爲 True ,這列就是表的主鍵.若是沒有定義 __tablename__ ,SQLAlchemy 會使用一個默認名字 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

__repr__&__str__flask

最經常使用的SQLAlchemy列類型bootstrap

類型名 Python類型 說 明
Integer int 普通整數,通常是 32 位
SmallInteger int 取值範圍小的整數,通常是 16 位
BigInteger int 或 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 一組字符串
PickleType 任何 Python 對象 自動使用 Pickle 序列化
LargeBinary str 二進制文件

最常使用的SQLAlchemy列選項session

選項名 說 明
primary_key 若是設爲 True ,這列就是表的主鍵
unique 若是設爲 True ,這列不容許出現重複的值
index 若是設爲 True ,爲這列建立索引,提高查詢效率
nullable 若是設爲 True ,這列容許使用空值;若是設爲 False ,這列不容許使用空值
default 爲這列定義默認值

關係表達

關係型數據庫使用關係把不一樣表中的行聯繫起來。app

  • 一對多
class Role(db.Model): # ... users = db.relationship('User', backref='role')#添加到 Role 模型中的 users 屬性表明這個關係的面向對象視角。對於一個 Role 類的實例,其 users 屬性將返回與角色相關聯的用戶組成的列表。db.relationship() 的第一個參數表,若是模型類還沒有定義,可以使用字符串形式指定。db.relationship() 中的 backref 參數向 User 模型中添加一個 role 屬性,從而定義反向關係。這一屬性可替代 role_id 訪問 Role 模型,此時獲取的是模型對象 class User(db.Model): # ... role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))#關係使用 users 表中的外鍵鏈接了兩行。添加到 User 模型中的 role_id 列被定義爲外鍵,就是這個外鍵創建起了關係。傳給 db.ForeignKey() 的參數 'roles.id' 代表,這列的值是 roles 表中行的 id 值。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

db.relationship() 都能自行找到關係中的外鍵,但有時卻沒法決定把哪一列做爲外鍵。若是 User 模型中有兩個或以上的列定義爲 Role 模型的外鍵,SQLAlchemy 就不知道該使用哪列。若是沒法決定外鍵,你就要爲 db.relationship() 提供額外參數,從而肯定所用外鍵

經常使用的SQLAlchemy關係選項

選項名 說 明
backref 在關係的另外一個模型中添加反向引用
primaryjoin 明確指定兩個模型之間使用的聯結條件。只在模棱兩可的關係中須要指定
lazy 指定如何加載相關記錄。可選值有 select (首次訪問時按需加載)、 immediate (源對象加載後就加載)、 joined (加載記錄,但使用聯結)、 subquery (當即加載,但使用子查詢),noload (永不加載)和 dynamic (不加載記錄,但提供加載記錄的查詢)
uselist 若是設爲 Fales ,不使用列表,而使用標量值
order_by 指定關係中記錄的排序方式
secondary 指定 多對多 關係中關係表的名字
secondaryjoin SQLAlchemy 沒法自行決定時,指定多對多關係中的二級聯結條件
  • 一對一 
    一對一關係能夠用前面介紹的一對多關係表示,但調用 db.relationship() 時要把 uselist 設爲 False ,把「多」變成「一」。

  • 多對多

tags = db.Table('tags', db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')), db.Column('page_id', db.Integer, db.ForeignKey('page.id')) ) class Page(db.Model): id = db.Column(db.Integer, primary_key=True) tags = db.relationship('Tag', secondary=tags, backref=db.backref('pages', lazy='dynamic')) class Tag(db.Model): id = db.Column(db.Integer, primary_key=True)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

數據庫操做

  • 建立表
python hello.py shell
>>> from hello import db >>> db.create_all()
  • 1
  • 2
  • 3
  • 刪除表
db.drop_all()
  • 1
  • 插入行
#建立對象,模型的構造函數接受的參數是使用關鍵字參數指定的模型屬性初始值。 admin_role = Role(name='Admin') user_role = Role(name='User') user_susan = User(username='susan', role=user_role)#role 屬性也可以使用,雖然它不是真正的數據庫列,但倒是一對多關係的高級表示。 user_john = User(username='john', role=admin_role) #這些新建對象的 id 屬性並無明確設定,由於主鍵是由 Flask-SQLAlchemy 管理的。 print(admin_role.id)#None #經過數據庫會話管理對數據庫所作的改動,在 Flask-SQLAlchemy 中,會話由 db.session 表示。 ##首先,將對象添加到會話中 db.session.add(admin_role) db.session.add(user_role) db.session.add(user_susan) db.session.add(user_john) #簡寫:db.session.add_all([admin_role, user_role, user_john, user_susan]) ##經過提交會話(事務),將對象寫入數據庫 db.session.commit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

會話提交

數據庫會話能保證數據庫的一致性。提交操做使用原子方式把會話中的對象所有寫入數據庫。若是在寫入會話的過程當中發生了錯誤,整個會話都會失效。 
數據庫會話也可 回滾 。調用 db.session.rollback() 後,添加到數據庫會話中的全部對象都會還原到它們在數據庫時的狀態。

  • 修改行
admin_role.name = 'Administrator' db.session.add(admin_role) session.commit()
  • 1
  • 2
  • 3
  • 刪除行
db.session.delete(mod_role)
session.commit()
  • 1
  • 2
  • 查詢行

    • 查詢所有。Role.query.all()
    • 條件查詢(使用過濾器)。User.query.filter_by(role=user_role).all()
    user_role = Role.query.filter_by(name='User').first()#filter_by() 等過濾器在 query 對象上調用,返回一個更精確的 query 對象。
    • 1

    經常使用過濾器

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

最常使用的SQLAlchemy查詢執行函數

方 法 說 明
all() 以列表形式返回查詢的全部結果
first() 返回查詢的第一個結果,若是沒有結果,則返回 None
first_or_404() 返回查詢的第一個結果,若是沒有結果,則終止請求,返回 404 錯誤響應
get() 返回指定主鍵對應的行,若是沒有對應的行,則返回 None
get_or_404() 返回指定主鍵對應的行,若是沒找到指定的主鍵,則終止請求,返回 404 錯誤響應
count() 返回查詢結果的數量
paginate() 返回一個 Paginate 對象,它包含指定範圍內的結果
  • 關係查詢

    #執行 user_role.users 表達式時,隱含的查詢會調用 all() 返回一個用戶列表。 query 對象是隱藏的,所以沒法指定更精確的查詢過濾器。 users = user_role.users #修改了關係的設置,加入了 lazy = 'dynamic' 參數,從而禁止自動執行查詢 class Role(db.Model): users = db.relationship('User', backref='role', lazy='dynamic') #順序排列 user_role.users.order_by(User.username).all()
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

在視圖函數中操做數據庫

@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: session['known'] = True session['name'] = form.name.data form.name.data = '' return redirect(url_for('index')) return render_template('index.html', form = form, name = session.get('name'), known = session.get('known', False))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

修改模板

{ % 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 % }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

集成 Python shell

讓 Flask-Script 的 shell 命令自動導入特定的對象

from flask.ext.script import Shell def make_shell_context(): return dict(app=app, db=db, User=User, Role=Role) manager.add_command("shell", Shell(make_context=make_shell_context))
  • 1
  • 2
  • 3
  • 4

make_shell_context() 函數註冊了程序、數據庫實例以及模型,所以這些對象能直接導入 shell

使用 Flask-Migrate 實現數據庫遷移

建立遷移倉庫

pip install flask-migrate
  • 1

配置

from flask.ext.migrate import Migrate, MigrateCommand # ... migrate = Migrate(app, db) manager.add_command('db', MigrateCommand)
  • 1
  • 2
  • 3
  • 4

在維護數據庫遷移以前,要使用 init 子命令建立遷移倉庫

python hello.py db init
  • 1

建立遷移腳本

python hello.py db migrate -m "initial migration"
  • 1

更新數據庫

python hello.py db upgrade
相關文章
相關標籤/搜索