flask-sqlalchemy用法詳解

一. 安裝

$ pip install flask-sqlalchemy 

二. 配置

配置選項列表 :css

選項 說明
SQLALCHEMY_DATABASE_URI 用於鏈接的數據庫 URI 。例如:sqlite:////tmp/test.db 或 mysql://username:password@server/db
SQLALCHEMY_BINDS 一個映射 binds 到鏈接 URI 的字典。更多 binds 的信息見 用 Binds 操做多個數據庫 。
SQLALCHEMY_ECHO 若是設置爲 Ture , SQLAlchemy 會記錄全部 發給 stderr 的語句,這對調試有用。
SQLALCHEMY_RECORD_QUERIES 能夠用於顯式地禁用或啓用查詢記錄。查詢記錄 在調試或測試模式自動啓用。更多信息見 get_debug_queries() 。
SQLALCHEMY_TRACE_MODIFYCATIONS=False #是否追蹤對象的修改

SQLALCHEMY_NATIVE_UNICODE | 能夠用於顯式禁用原生 unicode 支持。當使用 不合適的指定無編碼的數據庫默認值時,這對於 一些數據庫適配器是必須的(好比 Ubuntu 上某些版本的 PostgreSQL )。|
| SQLALCHEMY_POOL_SIZE | 數據庫鏈接池的大小。默認是引擎默認值(一般 是 5 ) |
| SQLALCHEMY_POOL_TIMEOUT | 設定鏈接池的鏈接超時時間。默認是 10 。 |
| SQLALCHEMY_POOL_RECYCLE | 多少秒後自動回收鏈接。這對 MySQL 是必要的, 它默認移除閒置多於 8 小時的鏈接。注意若是 使用了 MySQL , Flask-SQLALchemy 自動設定這個值爲 2 小時。|html

  1.  
    app.config[ "SQLALCHEMY_DATABASE_URI"] = DATABASE_URI
  2.  
    app.config[ "SQLALCHEMY_COMMIT_ON_TEARDOWN"] = True/False # 每次請求結束後都會自動提交數據庫中的變更.
  3.  
     
  4.  
    app.config[ ""] =
  5.  
    app.config[ ""] =
  6.  
    app.config[ ""] =
  7.  
    app.config[ ""] =
  8.  
     
  9.  
    DATABASE_URI :
  10.  
    mysql : mysql://username:password@hostname/database
  11.  
     
  12.  
    pgsql : postgresql://username:password@hostname/database
  13.  
     
  14.  
    sqlite(linux) : sqlite:////absolute/path/to/database
  15.  
     
  16.  
    sqlite(windows) : sqlite:///c:/absolute/path/to/database

三. 初始化示例

  1.  
    from flask import Flask
  2.  
    from flask_sqlalchemy import SQLAlchemy
  3.  
    base_dir = os.path.abspath(os.path.dirname(__file__))
  4.  
     
  5.  
    app = Flask(__name__)
  6.  
     
  7.  
    app.config[ "SQLALCHEMY_DATABASE_URI"] = 'sqlite:///' + os.path.join(base_dir, 'data.sqlite')
  8.  
    app.config[ "SQLALCHEMY_COMMIT_ON_TEARDOWN"] = True
  9.  
     
  10.  
    db = SQLAlchemy(app)

四. 定義模型

模型 表示程序使用的持久化實體. 在 ORM 中, 模型通常是一個 Python 類, 類中的屬性對應數據庫中的表.python

Flaks-SQLAlchemy 建立的數據庫實例爲模型提供了一個基類以及一些列輔助類和輔助函數, 可用於定義模型的結構.mysql

  1.  
    db.Model # 建立模型,
  2.  
    db.Column # 建立模型屬性.

模型屬性類型 :linux

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

經常使用 SQLAlchemy 列選項sql

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

Flask-SQLAlchemy 要求每一個模型都要定義主鍵, 這一列一般命名爲 id .shell

示例 :數據庫

  1.  
    class Role(db.Model):
  2.  
    __tablename__ = "roles"
  3.  
    id = db.Column(db.Integer, primary_key= True)
  4.  
    name = db.Column(db.String( 64), unique=True)
  5.  
     
  6.  
    def __repr__(self):
  7.  
    """非必須, 用於在調試或測試時, 返回一個具備可讀性的字符串表示模型."""
  8.  
    return '<Role %r>' % self.name
  9.  
     
  10.  
    class User(db.Model):
  11.  
    __tablename__ = 'users'
  12.  
    id = db.Column(db.Integer, primary_key= True)
  13.  
    username = db.Column(db.String( 64), unique=True, index=True)
  14.  
     
  15.  
    def __repr__(self):
  16.  
    """非必須, 用於在調試或測試時, 返回一個具備可讀性的字符串表示模型."""
  17.  
    return '<Role %r>' % self.username

五. 關係

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

經常使用 SQLAlchemy 關係選項 :windows

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

1) 一對多

原理 : 在 「多」 這一側加入一個外鍵, 指定 「一」 這一側聯結的記錄.

示例代碼 : 一個角色可屬於多個用戶, 而每一個用戶只能有一個角色.

  1.  
    class Role(db.Model):
  2.  
    # ...
  3.  
    users = db.relationship( 'User', backref='role')
  4.  
     
  5.  
    class User(db.Model):
  6.  
    # ...
  7.  
    role_id = db.Column(db.Integer, db.ForeignKey( 'roles.id')) # 外鍵關係.
  8.  
     
  9.  
     
  10.  
    ###############
  11.  
    db.ForeignKey( 'roles.id') : 外鍵關係,
  12.  
     
  13.  
    Role.users = db.relationship( 'User', backref='role') : 表明 外鍵關係的 面向對象視角. 對於一個 Role 類的實例, 其 users 屬性將返回與角色相關聯的用戶組成的列表.
  14.  
    db.relationship() 第一個參數表示這個關係的另外一端是哪一個模型.
  15.  
    backref 參數, 向 User 模型添加了一個 role 數據屬性, 從而定義反向關係. 這一屬性可替代 role_id 訪問 Role 模型, 此時獲取的是模型對象, 而不是外鍵的值.

2) 多對多

最複雜的關係類型, 須要用到第三章表, 即 關聯表 , 這樣多對多關係能夠分解成原表和關聯表之間的兩個一對多關係.

查詢多對多關係分兩步 : 遍歷兩個關係來獲取查詢結果.

代碼示例:

  1.  
    registrations = db.Table( "registrations",
  2.  
    db.Column( "student_id", db.Integer, db.ForeignKey("students.id")),
  3.  
    db.Column( "class_id", db.Integer, db.ForeignKey("classes.id"))
  4.  
    )
  5.  
     
  6.  
    class Student(db.Model):
  7.  
    __tablename__ = "students"
  8.  
    id = db.Column(db. Integer, primary_key=True)
  9.  
    name = db.Column(db. String)
  10.  
    classes = db.relationship( "Class",
  11.  
    secondary=registrations,
  12.  
    backref=db.backref( "students", lazy="dynamic"),
  13.  
    lazy= "dynamic")
  14.  
     
  15.  
    class Class(db.Model):
  16.  
    __tablename__ = "classes"
  17.  
    id = db.Column(db. Integer, primary_key=True)
  18.  
    name = db.Column(db. String)

多對多關係仍然使用定義一對多關係的 db.relationship() 方法進行定義, 但在多對多關係中, 必須把 secondary 參數設爲 關聯表.

多對多關係能夠在任何一個類中定義, backref 參數會處理好關係的另外一側.

關聯表就是一個簡單的表, 不是模型, SQLAlchemy 會自動接管這個表.

classes 關係使用列表語義, 這樣處理多對多關係比較簡單.

Class 模型的 students 關係有 參數 db.backref() 定義. 這個關係還指定了 lazy 參數, 因此, 關係兩側返回的查詢均可接受額外的過濾器.

自引用關係
自引用關係能夠理解爲 多對多關係的特殊形式 : 多對多關係的兩邊由兩個實體變爲 一個實體.

高級多對多關係
使用多對多關係時, 每每須要存儲所聯兩個實體之間的額外信息. 這種信息只能存儲在關聯表中. 對用戶之間的關注來講, 能夠存儲用戶關注另外一個用戶的日期, 這樣就能按照時間順序列出全部關注者.

爲了能在關係中處理自定義的數據, 必須提高關聯表的地位, 使其變成程序可訪問的模型.

關注關聯表模型實現:

  1.  
    class Follow(db.Model):
  2.  
    __tablename__ = "follows"
  3.  
    follower_id = db.Column(db. Integer, db.ForeignKey("users.id"), primary_key=True)
  4.  
    followed_id = db.Column(db. Integer, db.ForeignKey("users.id"), primary_key=True)
  5.  
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)
  6.  
     
  7.  
    # SQLAlchemy 不能直接使用這個關聯表, 由於若是這個作程序就沒法訪問其中的自定義字段. 相反的, 要把這個多對多關係的左右兩側拆分紅兩個基本的一對多關係, 並且要定義成標準的關係.

使用兩個一對多關係實現的多對多關係:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class User(UserMixin, db.Model):
    # ...
    followd = db.relationship("Follow",
                              foreign_keys=[Follow.follower_id],
                              backref=db.backref("follower", lazy="joined"),
                              lazy="dynamic",
                              cascade="all, delete-orphan")
    followrs = db.relationship("Follow",
                              foreign_keys=[Follow.followed_id],
                              backref=db.backref("followed", lazy="joined"),
                              lazy="dynamic",
                              cascade="all, delete-orphan")

# 這段代碼中, followed 和 follower 關係都定義爲 單獨的 一對多關係. 
# 注意: 爲了消除外鍵歧義, 定義關係是必須使用可選參數 foreign_keys 指定的外鍵. 並且 db.backref() 參數並非指定這兩個關係之間的引用關係, 而是回引 Follow 模型. 回引中的 lazy="joined" , 該模式能夠實現當即從鏈接查詢中加載相關對象.
# 這兩個關係中, user 一側設定的 lazy 參數做用不同. lazy 參數都在 "一" 這一側設定, 返回的結果是 "多" 這一側中的記錄. dynamic 參數, 返回的是查詢對象.
# cascade 參數配置在父對象上執行的操做相關對象的影響. 好比, 層疊對象可設定爲: 將用戶添加到數據庫會話後, 要自定把全部關係的對象都添加到會話中. 刪除對象時, 默認的層疊行爲是把對象聯結的全部相關對象的外鍵設爲空值. 但在關聯表中, 刪除記錄後正確的行爲是把執行該記錄的實體也刪除, 由於這樣纔能有效銷燬聯結. 這就是 層疊選項值 delete-orphan 的做用. 設爲 all, delete-orphan 的意思是啓動全部默認層疊選項, 而且還要刪除孤兒記錄.

3) 一對一

能夠看作特殊的 一對多 關係. 但調用 db.relationship() 時 要把 uselist 設置 False, 把 多變爲 一 .

4) 多對一

將 一對多 關係,反過來便可, 也是 一對多關係.

六. 數據庫操做

1) 建立數據庫及數據表

建立數據庫

db.create_all() 

示例 :
$ python myflask.py shell
> from myflask import db
> db.create_all()

若是使用 sqlite , 會在 SQLALCHEMY_DATABASE_URI 指定的目錄下 多一個文件, 文件名爲該配置中的文件名.

若是數據庫表已經存在於數據庫中, 那麼 db.create_all() 不會建立或更新這個表.

更新數據庫
方法一 :
先刪除, 在建立 –> 原有數據庫中的數據, 都會消失.

  1.  
    > db.drop_all()
  2.  
    > db.create_all()

方法二 :
數據庫遷移框架 : 能夠跟自動數據庫模式的變化, 而後增量式的把變化應用到數據庫中.

SQLAlchemy 的主力開發人員編寫了一個 遷移框架 Alembic, 除了直接使用 Alembic wait, Flask 程序還可以使用 Flask-Migrate 擴展, 該擴展對 Alembic 作了輕量級包裝, 並集成到 Flask-Script 中, 全部操做都經過 Flaks-Script 命令完成.

① 安裝 Flask-Migrate
$ pip install flask-migrate

② 配置

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

③ 數據庫遷移
a. 使用 init 自命令建立遷移倉庫.
$ python myflask.py db init # 該命令會建立 migrations 文件夾, 全部遷移腳本都存在其中.

  1.  
    b. 建立數據路遷移腳本.
  2.  
    $ python myflask.py db revision # 手動建立 Alemic 遷移
  3.  
    建立的遷移只是一個骨架, upgrade() 和 downgrade() 函數都是空的. 開發者須要使用 Alembic 提供的 Operations 對象指令實現具體操做.
  4.  
     
  5.  
    $ python myflask.py db migrate -m COMMONT # 自動建立遷移.
  6.  
    自動建立的遷移會根據模型定義和數據庫當前的狀態之間的差別生成 upgrade() 和 downgrade() 函數的內容.
  7.  
     
  8.  
    ** 自動建立的遷移不必定老是正確的, 有可能漏掉一些細節, 自動生成遷移腳本後必定要進行檢查.
  9.  
     
  10.  
     
  11.  
    c. 更新數據庫
  12.  
    $ python myflask.py db upgrade # 將遷移應用到數據庫中.

2) 插入行

模型的構造函數, 接收的參數是使用關鍵字參數指定的模型屬性初始值. 注意, role 屬性也可以使用, 雖然他不是真正的數據庫列, 但倒是一對多關係的高級表示. 這些新建對象的 id 屬性並無明確設定, 由於主鍵是由 Flask-SQLAlchemy 管理的. 如今這些對象只存在於 Python 解釋器中, 還沒有寫入數據庫.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
>> from myflask import db, User, Role

>> 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=mod_role)

>> user_david = User(username="david", role=user_role)

>> admin_role.name
'Admin'

>> admin_role.id
None

---------

>> db.session.add_all([admin_role, mod_role, user_role, user_john, user_susan, user_david])   # 把對象添加到會話中.
>> db.session.commit()      # 把對象寫入數據庫, 使用 commit() 提交會話.

 

3) 修改行

  1.  
    >> admin_role = "Administrator"
  2.  
    >> db.session.add(admin_role)
  3.  
    >> db.session.commit()

4) 刪除行

  1.  
    >> db.session.delete(mod_role)
  2.  
    >> db.session.commit()

5) 查詢行

Flask-SQLAlchemy 爲每一個模型類都提供了 query 對象.

獲取表中的全部記錄

  1.  
    >> Role.query.all()
  2.  
    [<Role u'Admin'>, <Role u'Moderator'>, <Role u'User'>]
  3.  
    >> User.query.all()
  4.  
    [<Role u'john'>, <Role u'susan'>, <Role u'david'>]

查詢過濾器

filter_by() 等過濾器在 query 對象上調用, 返回一個更精確的 query 對象. 多個過濾器能夠一塊兒調用, 直到獲取到所需的結果.

  1.  
    >> User.query.filter_by(role=user_role).all() # 以列表形式,返回全部結果,
  2.  
    >> User.query.filter_by(role=user_role).first() # 返回結果中的第一個.

filter() 對查詢結果過濾,比」filter_by()」方法更強大,參數是布爾表達式

  1.  
    # WHERE age< 20
  2.  
    users = User.query.filter(User.age< 20)
  3.  
    # WHERE name LIKE 'J%' AND age<20
  4.  
    users = User.query.filter(User. name.startswith('J'), User.age<20)

查詢過濾器 :

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

查詢執行函數 :

方法 說明
all() 以列表形式返回查詢的全部結果
first() 返回查詢的第一個結果,若是沒有結果,則返回 None

first_or_404() | 返回查詢的第一個結果,若是沒有結果,則終止請求,返回 404 錯誤響應 | |
| get() | 返回指定主鍵對應的行,若是沒有對應的行,則返回 None |
get_or_404() | 返回指定主鍵對應的行,若是沒找到指定的主鍵,則終止請求,返回 404 | |錯誤響應
| count() | 返回查詢結果的數量 |
| paginate() | 返回一個 Paginate 對象,它包含指定範圍內的結果 |

6) 會話管理, 事務管理

單個提交

  1.  
    >> db.session.add(ONE)
  2.  
    >> db.session.commit()

多個提交

  1.  
    >> db.session.add_all([LIST_OF_MEMBER])
  2.  
    >> db.session.commit()

刪除會話

  1.  
    >> db.session.delete(mod_role)
  2.  
    >> db.session.commit()

事務回滾 : 添加到數據庫會話中的全部對象都會還原到他們在數據庫時的狀態.

>> db.session.rollback() 

七. 視圖函數中操做數據庫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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 = ""             # why empty it ?
        return redirect(url_for("index"))
    return render_template("index.html", current_time=datetime.utcnow(), form=form, name=session.get("name"), known=session.get("known"))

八. 分頁對象 Pagination

1. paginate() 方法

paginate() 方法的返回值是一個 Pagination 類對象, 該類在 Flask-SQLAlchemy 中定義, 用於在模板中生成分頁連接.

  1.  
    paginate(頁數[,per_page= 20, error_out=True])
  2.  
    頁數 : 惟一必須指定的參數,
  3.  
    per_page : 指定每頁現實的記錄數量, 默認 20.
  4.  
    error_out : True 若是請求的頁數超出了返回, 返回 404 錯誤; False 頁數超出範圍時返回一個,空列表.

示例代碼:

1
2
3
4
5
6
7
8
@main.route("/", methods=["GET", "POST"])
def index():
    # ...
    page = request.args.get('page', 1, type=int)    # 渲染的頁數, 默認第一頁, type=int 保證參數沒法轉換成整數時, 返回默認值.
    pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=current_app.config["FLASKY_POSTS_PER_PAGE"], error_out=False)

    posts = pagination.items
    return render_template('index.html', form=form, posts=posts,pagination=pagination)

 

2. 分頁對象的屬性及方法:

Flask_SQLAlchemy 分頁對象的屬性:

屬性 說明
items 當前分頁中的記錄
query 分頁的源查詢
page 當前頁數
prev_num 上一頁的頁數
next_num 下一頁的頁數
has_next 若是有下一頁, 返回 True
has_prev 若是有上一頁, 返回 True
pages 查詢獲得的總頁數
per_page 每頁顯示的記錄數量
total 查詢返回的記錄總數

在分頁對象可調用的方法:

方法 說明
iter_pages(left_edge=2,left_current=2,right_current=5,right_edge=2) 一個迭代器, 返回一個在分頁導航中顯示的頁數列表. 這個列表的最左邊顯示 left_edge 頁, 當前頁的左邊顯式 left_current 頁, 當前頁的右邊顯示 right_currnt 頁, 最右邊顯示 right_edge 頁. 如 在一個 100 頁的列表中, 當前頁爲 50 頁, 使用默認配置, 該方法返回如下頁數 : 1, 2, None, 48,49,50,51,52,53,54,55, None, 99 ,100. None 表示頁數之間的間隔.
prev() 上一頁的分頁對象
next() 下一頁的分頁對象

3. 在模板中與 BootStrap 結合使用示例

使用 Flaks-SQLAlchemy 的分頁對象與 Bootstrap 中的分頁 CSS, 能夠輕鬆的構造出一個 分頁導航.

分頁模板宏 _macros.html : 建立一個 Bootstrap 分頁元素, 即一個有特殊樣式的無序列表.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{% macro pagination_widget(pagination,endpoint) %}
<ul class="pagination">
    <li {% if not pagination.has_prev %} class="disabled" {% endif %}>
        <a href="{% if pagination.has_prev %}{{url_for(endpoint, page=paginatin.page - 1, **kwargs)}}{% else %}#{% endif %}">
            &laquo;
        </a>
    </li>
    {% for p in pagination,.iter_pages() %}
        {% if p %}
            {% if p == pagination.page %}
            <li class="active">
                <a href="{{ url_for(endpoint, page=p, **kwargs) }}">{{p}}</a>
            </li>
            {% else %}
            <li>
                <a href="{{ url_for(endpoint, page = p, **kwargs) }}">{{p}}</a>
            </li>
            {% endif %}
        {% else %}
        <li class="disabled"><a href="#">&hellip;</a> </li>
        {% endif %}
    {% endfor %}
    <li {% if not pagination.has_next %} class="disabled" {% endif%}>
        <a href="{% if paginatin.has_next %}{{ url_for(endpoint, page=pagination.page+1, **kwargs) }}{% else %}#{% endif %}">
            &raquo;
        </a>
    </li>
</ul>
{% endmacro %}

導入使用分頁導航

1
2
3
4
5
6
{% extends "base.html" %}
{% import "_macros.html" as macros %}
...
<div class="pagination">
    {{ macro.pagination_widget(pagination, ".index")}}
</div>

 

九. 監聽事件

1. set 事件

示例代碼 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from markdown import markdown
import bleach

class Post(db.Model):
    # ...
    body = db.Colume(db.Text)
    body_html = db.Column(db.Text)
    # ...

    @staticmethod
    def on_changeed_body(target, value, oldvalue, initiator):
        allowed_tags = ["a", "abbr", "acronym", "b", "blockquote", "code", "em",
                        "i", "li", "ol", "pre", "strong", "ul", "h1", "h2","h3","h4","p"]
        target.body_html = bleach.linkify(bleach.clean(markdown(value, output_format="html"), tags=allowed_tags, strip=True))

db.event.listen(Post.body, "set", Post.on_changeed_body) 
# on_changed_body 函數註冊在 body 字段上, 是 SQLIAlchemy "set" 事件的監聽程序, 
# 這意味着只要這個類實例的 body 字段設了新值, 函數就會自動被調用. 
# on_changed_body 函數把 body 字段中的文本渲染成 HTML 格式, 
# 結果保存在 body_html 中, 自動高效的完成 Markdown 文本到 HTML 的轉換.

 

十. 記錄慢查詢.

十一. Binds 操做多個數據庫

十二. 其餘

1. ORM 在查詢時作初始化操做

當 SQLIAlchemy ORM 從數據庫查詢數據時, 默認不調用__init__ 方法, 其底層實現了 Python 類的 __new__() 方法, 直接實現 對象實例化, 而不是經過 __init__ 來實例化對象.

若是須要在查詢時, 依舊但願實現一些初始化操做, 可使用 orm.reconstructor() 裝飾器或 實現 InstanceEvents.load() 監聽事件.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# orm.reconstructor
from sqlalchemy import orm

class MyMappedClass(object):
    def __init__(self, data):
        self.data = data

        # we need stuff on all instances, but not in the database.
        self.stuff = []

    @orm.reconstructor
    def init_on_load(self):
        self.stuff = []

# InstanceEvents.load()
from sqlalchemy import event
## standard decorator style

@event.listens_for(SomeClass, 'load')
def receive_load(target, context):
    "listen for the 'load' event"

    # ... (event handling logic) ...

 

若是隻是但願在從數據庫查詢生成的對象中包含某些屬性, 也可使用 property 實現:

1
2
3
4
5
6
7
8
9
10
11
class AwsRegions(db.Model):
    name=db.Column(db.String(64))
    ...

    @property
    def zabbix_api(self):
        return ZabbixObj(zabbix_url)

    @zabbix_api.setter
    def zabbix_api(self):
        raise ValueError("zabbix can not be setted!")

轉自:https://www.pyfdtic.com/2018/03/19/flaskExt--flask-sqlalchemy/

相關文章
相關標籤/搜索