Flask-SQLAlchemy 使用起来非常有趣,对于基本应用十分容易使用,并且对于大型项目易于扩展。有关完整的指南,请参阅 SQLAlchemy 的 API 文档。
常见情况下对于只有一个 Flask 应用,所有您需要做的事情就是创建 Flask 应用,选择加载配置接着创建 SQLAlchemy 对象时候把 Flask 应用传递给它作为参数。
一旦创建,这个对象就包含 sqlalchemy 和 sqlalchemy.orm 中的所有函数和助手。此外它还提供一个名为 Model 的类,用于作为声明模型时的 delarative 基类:
# settings.py
DIALECT = 'mysql'
DRIVER = 'pymysql'
USERNAME = 'root'
PASSWORD = '808069'
HOST = '127.0.0.1'
PORT = '3306'
DATABASE = 'cms'
SQLALCHEMY_DATABASE_URI = '{}+{}://{}:{}@{}:{}/{}?charset=utf8'.format(
DIALECT,DRIVER,USERNAME,PASSWORD,HOST,PORT,DATABASE
)
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
SQLALCHEMY_TRACK_MODIFICATIONS = True
# manage.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
# models.py
from manage import db
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.INTEGER,primary_key=True)
username = db.Column(db.String(80),unique=True)
password = db.Column(db.String(80),nullable=False)
class CodeCountRecord(db.Model):
__tablename = 'codecountrecord'
id = db.Column(db.INTEGER,primary_key=True)
count = db.Column(db.INTEGER)
data = db.Column(db.DATE)
user = db.Column(db.ForeignKey('user.id'))
db.create_all()
在查询数据之前我们必须先插入数据。
您的所有模型都应该有一个构造函数,如果您 忘记了,请确保加上一个。
只有您自己使用这些构造函数而 SQLAlchemy 在内部不会使用它,
所以如何定义这些构造函数完全取决与您。
向数据库插入数据分为三个步骤:
创建 Python 对象
把它添加到会话 :这里的会话不是 Flask 的会话,而是 Flask-SQLAlchemy 的会话。
它本质上是一个 数据库事务的加强版本。
提交会话
把对象添加到会话之前, SQLAlchemy 基本不考虑把它加到事务中。
这是好事,因为您仍然可以放弃更改。
调用 add() 函数会添加对象。
它会发出一个 INSERT 语句给数据库,但是由于事务仍然没有提交,您不会立即得到返回的 ID 。
如果您提交,您的用户会有一个 ID:
from cms.models import User
from manage import db
def create_user():
# 创建一个新用户对象
user = User()
user.username = 'fuyong'
user.password = '123'
# 将新创建的用户添加到数据库会话中
db.session.add(user)
# 将数据库会话中的变动提交到数据库中, 记住, 如果不 commit, 数据库中是没有变化的.
db.session.commit()
create_user()
def delete_user():
# 获取用户对象
user = User.query.filter_by(id=1).first()
# 删除用户
db.session.delete(user)
#提交数据库会话
db.session.commit()
delete_user()
def update_user():
# 获取用户对象
user = User.query.filter_by(id=2).first()
# 修改用户
user.password = '123567'
#提交数据库会话
db.session.commit()
update_user()
Flask-SQLAlchemy 在您的 Model 类上提供了 query 属性。
当您访问它时,您会得到一个新的所有记录的查询对象。
在使用 all() 或者 first() 发起查询之前可以使用方法 filter() 来过滤记录。
如果您想要用主键查询的话,也可以使用 get()。
def select_user():
# 查询所有用户
users_list = User.query.all()
# 查询用户名称为 fuyong 的第一个用户, 并返回用户实例,
# 因为之前定义数据库的时候定义用户名称唯一, 所以数据库中用户名称为 test 的应该只有一个.
user = User.query.filter_by(username='fuyong').first()
# or
user = User.query.filter(User.username == 'fuyong').first()
# 模糊查询, 查找用户名以abc 结尾的所有用户
users_list = User.query.filter(User.username.endsWith('g')).all()
# 查询用户名不是 fuyong 的第一个用户
user = User.query.filter(User.username != 'fuyong').first()
当您编写 Flask 视图函数,对于不存在的条目返回一个 404 错误是非常方便的。
因为这是一个很常见的问题,Flask-SQLAlchemy 为了解决这个问题提供了一个帮助函数。
可以使用 get_or_404() 来代替 get(),使用 first_or_404() 来代替 first()。
这样会抛出一个 404 错误,而不是返回 None:
解决办法就是另外创建一个ext.py文件,专门用来创建db,代码如下:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
db.init_app(app)
SQLAlchemy 连接到关系型数据库,关系型数据最擅长的东西就是关系。
如果您想要一对一关系,您可以把 uselist=False 传给 relationship() 。
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',uselist=False)
# lazy 决定了 SQLAlchemy 什么时候从数据库中加载数据:
# 'select' (默认值) 就是说 SQLAlchemy 会使用一个标准的 select 语句必要时一次加载数据。
# 'joined' 告诉 SQLAlchemy 使用 JOIN 语句作为父级在同一查询中来加载关系
# 'subquery' 类似 'joined' ,但是 SQLAlchemy 会使用子查询。
# 'dynamic' 在有多条数据的时候是特别有用的。不是直接加载这些数据,
# SQLAlchemy 会返回一个查询对象,在加载数据前您可以过滤(提取)它们。
# backref 是一个在 Address 类上声明新属性的简单方法。
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'))
问:您如何为反向引用(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')
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'))
如果您想要用多对多关系,您需要定义一个用于关系的辅助表。
对于这个辅助表, 强烈建议 不 使用模型,而是采用一个实际的表:
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)
tags = db.Table('tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
db.Column('page_id', db.Integer, db.ForeignKey('page.id'))
)
这里我们配置 Page.tags 加载后作为标签的列表,因为我们并不期望每页出现太多的标签。而每个 tag 的页面列表( Tag.pages)是一个动态的反向引用。 正如上面提到的,这意味着您会得到一个可以发起 select 的查询对象。
从 0.12 开始,Flask-SQLAlchemy 可以容易地连接到多个数据库。为了实现这个功能,预配置了 SQLAlchemy 来支持多个 “binds”。
下面的配置声明了三个数据库连接。特殊的默认值和另外两个分别名为 users(用于用户)和
appmeta 连接到一个提供只读访问应用内部数据的 sqlite 数据库):
SQLALCHEMY_DATABASE_URI = 'postgres://localhost/main'
SQLALCHEMY_BINDS = {
'users': 'mysqldb://localhost/users',
'appmeta': 'sqlite:path/to/appmeta.db'
}
create_all() 和 drop_all() 方法默认作用于所有声明的绑定(bind),包括默认的。
这个行为可以通过提供 bind 参数来定制。
它可以是单个绑定(bind)名, ‘all’ 指向所有绑定(binds)或一个绑定(bind)名的列表。
默认的绑定(bind)(SQLALCHEMY_DATABASE_URI) 名为 None:
>>> db.create_all()
>>> db.create_all(bind=['users'])
>>> db.create_all(bind='appmeta')
>>> db.drop_all(bind=None)
当您声明模型时,您可以用 bind_key 属性指定绑定(bind):
class User(db.Model):
__bind_key__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
bind key 存储在表中的 info 字典中作为 ‘bind_key’ 键值。
了解这个很重要,因为当您想要直接创建一个表对象时,您会需要把它放在那:
user_favorites = db.Table('user_favorites',
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('message_id', db.Integer, db.ForeignKey('message.id')),
info={'bind_key': 'users'}
)
如果您在模型上指定了 bind_key ,您可以用它们准确地做您想要的。
模型会自行连 接到指定的数据库连接。
官网详解
这部分文档记录了 Flask-SQLAlchemy 里的所有公开的类和函数。
__bind_key__:
__tablename__:
query:
query_class:
all()
order_by()
limit()
offset()
first()
first_or_404()
get()
get_or_404()
paginate()
class flask.ext.sqlalchemy.Pagination(query, page, per_page, total, items)¶
由BaseQuery.paginate()返回的内部帮助器类。
object = models.query.all().paginate()
'''
has_next
has_prev
items
iter_pages
next
next_num
page
pages
per_page
prev
prev_num
query
total
'''
flask.ext.sqlalchemy.get_debug_queries()
在调试模式下,Flask-SQLAlchemy将记录发送到数据库的所有SQL查询。
# 在配置文件中进行如下配置
SQLALCHEMY_RECORD_QUERIES=True
user.query.join()