flask-sqlalchemy用法詳解


一. 安裝

$ pip install flask-sqlalchemy 

二. 配置

配置選項列表 :

選項 說明
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 小時。|

  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 類, 類中的屬性對應數據庫中的表.

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

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

模型屬性類型 :

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

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

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

示例 :

  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

五. 關系

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

常用 SQLAlchemy 關系選項 :

選項名 說明
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/


免責聲明!

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



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