flask數據庫操作


Python 數據庫框架

大多數的數據庫引擎都有對應的 Python 包,包括開源包和商業包。Flask 並不限制你使用何種類型的數據庫包,因此可以根據自己的喜好選擇使用 MySQL、Postgres、SQLite、Redis、MongoDB 或者 CouchDB。

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

選擇數據庫框架的因素:

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

Flask-SQLAlchemy 管理數據庫

  • 安裝
pip install flask-sqlalchemy
  • 1

使用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

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

  • 配置
    程序使用的數據庫 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__

最常用的SQLAlchemy列類型

類型名 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列選項

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

關系表達

關系型數據庫使用關系把不同表中的行聯系起來。

  • 一對多
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




轉自:https://blog.csdn.net/sun_dragon/article/details/51719753


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM