在 flask 中, 很多人更喜歡通過 SQLAlchemy 來操作數據庫。這種情況下推薦使用包代替模塊, 把數據模型剝離到一個獨立的模塊中。這樣的做法不是必須的, 但是更加合理。
Flask-SQLAlchemy Extension
由於 SQLAlchemy 是一個通用的數據庫抽象層和 ORM, 它需要一些額外的配置, Flask 中有一個擴展來處理這些。
Declarative
SQLAchemy 中的 declarative extension 是最近出現的一種方法。這種方法允許你一次性定義表單和數據模型, 這和 Django 的工作方式類似。
下面是一個 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():
# import all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
import yourapplication.models
Base.metadata.create_all(bind=engine)
我們自己定義的數據模型只需要繼承上面代碼中的 Base 就可以了。這個地方不用擔心線程安全的問題,因爲 SQLAlchemy 已經通過 scoped_session 幫我們處理了。
我們只需要把下面的代碼放入我們的應用模塊中就可以以 declarative 的方式來使用 SQLAlchemy 了。Flask 會在 request 結束或者應用退出時自動關閉 session:
from yourapplication.database import db_session
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
下面的代碼是一個數據模型的例子(可以放入 models.py中, e.g.):
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():
>>> from yourapplication.database import init_db
>>> init_db()
向數據庫中插入記錄:
>>> from yourapplication.database import db_session
>>> from yourapplication.models import User
>>> u = User('admin', 'admin@localhost')
>>> db_session.add(u)
>>> db_session.commit()
查詢也很簡單:
>>> User.query.all()
[<User u'admin'>]
>>> User.query.filter(User.name == 'admin').first()
<User u'admin'>