1、连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1/test'app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = Truedb = SQLAlchemy(app)#SQLALCHEMY_COMMIT_ON_TEARDOWN 键,将其设为 True 时,每次请求结束后都会自动提交数据库中的变动。
2、声明模型
2.1 简单示例
class User(db.Model):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(80), unique=True)email = db.Column(db.String(120), unique=True)def __init__(self, username, email):self.username = usernameself.email = emaildef __repr__(self):return '<User %r>' % self.username#函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式
用 Column 来定义一列。列名就是赋值给那个变量的名称
Flask-SQLAlchemy 要求每个模型都要定义主键,这一列经常命名为 id。
主键用 primary_key=True 标记。可以把多个键标记为主键,此时它们作为复合主键。
列的类型是 Column 的第一个参数。常用的有:

- 常用的列选项有:

2.2 一对多(one-to-many)关系
- 关系使用 relationship() 函数表示。然而外键必须用类 sqlalchemy.schema.ForeignKey 来单独声明:
class Person(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(50))addresses = db.relationship('Address', backref='person',lazy='dynamic')class Address(db.Model):id = db.Column(db.Integer, primary_key=True)email = db.Column(db.String(50))person_id = db.Column(db.Integer, db.ForeignKey('person.id'))11111111
db.relationship()让它指向 Address 类并加载多个地址
backref 是一个在 Address 类上声明新属性的简单方法。您也可以使用 my_address.person 来获取使用该地址(address)的人(person)。lazy 决定了 SQLAlchemy 什么时候从数据库中加载数据:
‘select’ (默认值) 就是说 SQLAlchemy 会使用一个标准的 select 语句必要时一次加载数据。
‘joined’ 告诉 SQLAlchemy 使用 JOIN 语句作为父级在同一查询中来加载关系。
‘subquery’ 类似 ‘joined’ ,但是 SQLAlchemy 会使用子查询。
‘dynamic’ 在有多条数据的时候是特别有用的。不是直接加载这些数据,SQLAlchemy 会返回一个查询对象,在加载数据前您可以过滤(提取)它们。
常用的关系选项

- 如何为反向引用(backrefs)定义惰性(lazy)状态?使用 backref() 函数:
class User(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(50))addresses = db.relationship('Address',backref=db.backref('person', lazy='joined'), lazy='dynamic')
2.3 多对多(many-to-many)关系
- 想要用多对多关系,需要定义一个用于关系的辅助表。对于这个辅助表, 强烈建议不使用模型,而是采用一个实际的表:
tags = db.Table('tags',db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),db.Column('page_id', db.Integer, db.ForeignKey('page.id')))class Page(db.Model):id = db.Column(db.Integer, primary_key=True)tags = db.relationship('Tag', secondary=tags,backref=db.backref('pages', lazy='dynamic'))class Tag(db.Model):id = db.Column(db.Integer, primary_key=True)
- 这里我们配置 Page.tags 加载后作为标签的列表,因为我们并不期望每页出现太多的标签。而每个 tag 的页面列表( Tag.pages)是一个动态的反向引用。 正如上面提到的,这意味着您会得到一个可以发起 select 的查询对象。
3、数据库操作
3.1 创建表
>>> db.drop_all()#根据模型类创建数据库表>>> db.create_all()#删除数据库表
3.2 插入行
下面这段代码创建了一些角色和用户:>>> from hello import Role, User>>> 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=user_role)>>> user_david = User(username='david', role=user_role)在 Flask-SQLAlchemy 中,会话由 db.session 表示。准备把对象写入数据库之前,先要将其添加到会话中:>>> db.session.add(admin_role)>>> db.session.add(mod_role)>>> db.session.add(user_role)>>> db.session.add(user_john)>>> db.session.add(user_susan)>>> db.session.add(user_david)或者简写成:>>> db.session.add_all([admin_role, mod_role, user_role, user_john, user_susan, user_david])为了把对象写入数据库,要调用 commit() 方法提交会话:>>> db.session.commit()
3.3 修改行
下面这个例子把 "Admin" 角色重命名为 "Administrator":>>> admin_role.name = 'Administrator'>>> db.session.add(admin_role)>>> db.session.commit()
3.4 删除行
下面这个例子把 "Moderator" 角色从数据库中删除:>>> db.session.delete(mod_role)>>> db.session.commit()
3.5 查询行
- 最基本的模型查询是取回对应表中的所有记录:
>>> Role.query.all()[<Role u'Administrator'>, <Role u'User'>]>>> User.query.all()[<User u'john'>, <User u'susan'>, <User u'david'>]
- 查找角色为”User”的所有用户:
>>> User.query.filter_by(role=user_role).all() [<User u'susan'>, <User u'david'>]
- 加载名为”User”的用户角色:
>>> user_role = Role.query.filter_by(name='User').first()
filter_by()等过滤器在query对象上调用,返回一个更精确的query对象。
- 常用过滤器有:
在查询上应用指定的过滤器后,通过调用all()执行查询,以列表的形式返回结果。
- 常用查询执行函数有:

3、数据库操作
@app.route('/user/<username>')def show_user(username):user = User.query.filter_by(username=username).first_or_404()return render_template('show_user.html', user=user)
对于不存在的条目返回一个 404 错误是非常方便的。因为这是一个很常见的问题,Flask-SQLAlchemy 为了解决这个问题提供了一个帮助函数。可以使用 get_or_404() 来代替 get(),使用 first_or_404() 来代替 first()。这样会抛出一个 404 错误,而不是返回 None
