在 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'>