Flask 在 Flask 中使用 SQLAIchemy

2021-08-11 10:00 更新

很多人更傾向于使用 SQLAlchemy 進(jìn)行數(shù)據(jù)庫(kù)操作。在這種情況下,建議您使用 包的而不是模塊的方式組織您的應(yīng)用代碼,并將所有的模型放置到一個(gè)單獨(dú)的模塊中 (大型應(yīng)用)。盡管這并非必要,但是這么做將會(huì)讓程序的結(jié)構(gòu)更加 明晰。

使用 SQLAlchemy 有四種常用的方法,我們?cè)谙旅媪谐隽诉@幾種方法的基本使用 框架:

Flask-SQLAlchemy 擴(kuò)展

因?yàn)?SQLAlchemy 是一個(gè)常用的數(shù)據(jù)庫(kù)抽象層和數(shù)據(jù)庫(kù)關(guān)系映射包(ORM),并且需要 一點(diǎn)點(diǎn)設(shè)置才可以使用,因此存在一個(gè) Flask 擴(kuò)展幫助您操作它。如果您想要快速 開(kāi)始使用,那么我們建議您使用這種方法。

您可以從 PyPI 下載到 Flask-SQLAlchemy

顯式調(diào)用

SQLAlchemy 中的 declarative 擴(kuò)展是最新的使用 SQLAlchemy 的方法。它允許您 同時(shí)定義表和模型,就像 Django 一樣工作。除了下文所介紹的內(nèi)容外,我們建議您 參考 declarative 擴(kuò)展的官方文檔。

這是一個(gè) database.py 模塊的例子:

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()

def init_db():
    # 在這里導(dǎo)入所有的可能與定義模型有關(guān)的模塊,這樣他們才會(huì)合適地
    # 在 metadata 中注冊(cè)。否則,您將不得不在第一次執(zhí)行 init_db() 時(shí)
    # 先導(dǎo)入他們。
    import yourapplication.models
    Base.metadata.create_all(bind=engine)

為了定義您的模型,僅僅構(gòu)造一個(gè)上面代碼編寫(xiě)的 Base 類(lèi)的子類(lèi)。如果您好奇 為何我們?cè)谶@里不用擔(dān)心多線(xiàn)程的問(wèn)題(就像我們?cè)谙惹笆褂?g 對(duì)象操作 SQLite3 的例子一樣):那是因?yàn)?SQLAlchemy 已經(jīng)在 scoped_session 類(lèi)當(dāng)中為我們完成了這些任務(wù)。

在您的應(yīng)用當(dāng)中以一個(gè)顯式調(diào)用 SQLAlchemy , 您只需要將如下代碼放置在您應(yīng)用 的模塊中。Flask 將會(huì)在請(qǐng)求結(jié)束時(shí)自動(dòng)移除數(shù)據(jù)庫(kù)會(huì)話(huà):

from yourapplication.database import db_session

@app.teardown_request
def shutdown_session(exception=None):
    db_session.remove()

這是一個(gè)模型的例子(將代碼放入 models.py 或類(lèi)似文件中):

from sqlalchemy import Column, Integer, String
from yourapplication.database import Base

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), unique=True)
    email = Column(String(120), unique=True)

    def __init__(self, name=None, email=None):
        self.name = name
        self.email = email

    def __repr__(self):
        return '<User %r>' % (self.name)

您可以使用 init_db 函數(shù)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù):

>>> from yourapplication.database import init_db
>>> init_db()

按照如下方式將數(shù)據(jù)實(shí)體插入數(shù)據(jù)庫(kù):

>>> from yourapplication.database import db_session
>>> from yourapplication.models import User
>>> u = User('admin', 'admin@localhost')
>>> db_session.add(u)
>>> db_session.commit()

查詢(xún)代碼也很簡(jiǎn)單:

>>> User.query.all()
[<User u'admin'>]
>>> User.query.filter(User.name == 'admin').first()
<User u'admin'>

手動(dòng)實(shí)現(xiàn) ORM

手動(dòng)實(shí)現(xiàn) ORM (對(duì)象關(guān)系映射) 相比前面的顯式調(diào)用方法,既有一些優(yōu)點(diǎn),也有一些缺點(diǎn)。 主要差別在于這里的數(shù)據(jù)表和模型是分開(kāi)定義的,然后再將其映射起來(lái)。這提供了更大的靈活性, 但是會(huì)增加了代碼量。通常來(lái)說(shuō)它和上面顯式調(diào)用的工作的方式很相似,所以請(qǐng)確保您的應(yīng)用已經(jīng) 被合理分割到了包中的不同模塊中。

這是一個(gè) database.py 模塊的例子:

from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker

engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
metadata = MetaData()
db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))
def init_db():
    metadata.create_all(bind=engine)

與顯式調(diào)用相同,您需要在請(qǐng)求結(jié)束后關(guān)閉數(shù)據(jù)庫(kù)會(huì)話(huà)。將下面的代碼 放到您的應(yīng)用程序模塊中:

from yourapplication.database import db_session

@app.teardown_request
def shutdown_session(exception=None):
    db_session.remove()

下面是一個(gè)數(shù)據(jù)表和模型的例子(將他們放到 models.py 當(dāng)中):

from sqlalchemy import Table, Column, Integer, String
from sqlalchemy.orm import mapper
from yourapplication.database import metadata, db_session

class User(object):
    query = db_session.query_property()

    def __init__(self, name=None, email=None):
        self.name = name
        self.email = email

    def __repr__(self):
        return '<User %r>' % (self.name)

users = Table('users', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String(50), unique=True),
    Column('email', String(120), unique=True)
)
mapper(User, users)

查詢(xún)和插入操作和上面所給出的例子是一樣的。

SQL 抽象層

如果您僅用到數(shù)據(jù)庫(kù)系統(tǒng)和 SQL 抽象層,那么您只需要引擎部分:

from sqlalchemy import create_engine, MetaData

engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
metadata = MetaData(bind=engine)

然后您就可以像上文的例子一樣聲明數(shù)據(jù)表,或者像下面這樣自動(dòng)加載他們:

users = Table('users', metadata, autoload=True)

您可以使用 insert 方法插入數(shù)據(jù),我們需要先獲取一個(gè)數(shù)據(jù)庫(kù)連接,這樣 我們就可以使用“事務(wù)”了:

>>> con = engine.connect()
>>> con.execute(users.insert(), name='admin', email='admin@localhost')

SQLAlchemy 將會(huì)為我們自動(dòng)提交對(duì)數(shù)據(jù)庫(kù)的修改。

查詢(xún)數(shù)據(jù)可以直接通過(guò)數(shù)據(jù)庫(kù)引擎,也可以使用一個(gè)數(shù)據(jù)庫(kù)連接:

>>> users.select(users.c.id == 1).execute().first()
(1, u'admin', u'admin@localhost')

返回的結(jié)果也是字典樣式的元組:

>>> r = users.select(users.c.id == 1).execute().first()
>>> r['name']
u'admin'

您也可以將 SQL 語(yǔ)句的字符串傳入到 execute() 函數(shù)中:

>>> engine.execute('select * from users where id = :1', [1]).first()
(1, u'admin', u'admin@localhost')

更多 SQLAlchemy 相關(guān)信息,請(qǐng)參考 其網(wǎng)站.

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)