声明模型
通常下,Flask-SQLAlchemy 的行为就像一个来自 declarative
扩展配置正确的 declarative 基类。因此,我们强烈建议您阅读 SQLAlchemy 文档以获取一个全面的参考。尽管如此,我们这里还是给出了最常用的示例。
需要牢记的事情:
- 您的所有模型的基类叫做
db.Model
。它存储在您必须创建的 SQLAlchemy 实例上。 细节请参阅 快速入门。 - 有一些部分在 SQLAlchemy 上是必选的,但是在 Flask-SQLAlchemy 上是可选的。 比如表名是自动地为您设置好的,除非您想要覆盖它。它是从转成小写的类名派生出来的,即 “CamelCase” 转换为 “camel_case”。
简单示例
一个非常简单的例子:
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 = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
用 Column
来定义一列。列名就是您赋值给那个变量的名称。如果您想要在表中使用不同的名称,您可以提供一个想要的列名的字符串作为可选第一个参数。主键用 primary_key=True
标记。可以把多个键标记为主键,此时它们作为复合主键。
列的类型是 Column
的第一个参数。您可以直接提供它们或进一步规定(比如提供一个长度)。下面的类型是最常用的:
Integer | 一个整数 |
String (size) | 有长度限制的字符串 |
Text | 一些较长的 unicode 文本 |
DateTime | 表示为 Python datetime 对象的 时间和日期 |
Float | 存储浮点值 |
Boolean | 存储布尔值 |
PickleType | 存储为一个持久化的 Python 对象 |
LargeBinary | 存储一个任意大的二进制数据 |
一对多(one-to-many)关系
最为常见的关系就是一对多的关系。因为关系在它们建立之前就已经声明,您可以使用 字符串来指代还没有创建的类(例如如果 Person
定义了一个到 Article
的关系,而 Article
在文件的后面才会声明)。
关系使用 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'))
db.relationship()
做了什么?这个函数返回一个可以做许多事情的新属性。在本案例中,我们让它指向 Address 类并加载多个地址。它如何知道会返回不止一个地址?因为 SQLALchemy 从您的声明中猜测了一个有用的默认值。 如果您想要一对一关系,您可以把 uselist=False
传给 relationship()
。
那么 backref
和 lazy
意味着什么了?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')
多对多(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 的查询对象。