返回介绍

数据库关系

发布于 2025-01-02 21:53:49 字数 3645 浏览 0 评论 0 收藏 0

关系数据库擅长存储数据项之间的关系。 考虑用户发表动态的情况, 用户将在 user 表中有一个记录,并且这条用户动态将在 post 表中有一个记录。 标记谁写了一个给定的动态的最有效的方法是链接两个相关的记录。

一旦建立了用户和动态之间的关系,数据库就可以在查询中展示它。最小的例子就是当你看一条用户动态的时候需要知道是谁写的。一个更复杂的查询是, 如果你好奇一个用户时,你可能想知道这个用户写的所有动态。 Flask-SQLAlchemy 有助于实现这两种查询。

让我们扩展数据库来存储用户动态,以查看实际中的关系。 这是一个新表 post 的设计(译者注:实际表名分别为 user 和 post):

post 表将具有必须的 id 、用户动态的 bodytimestamp 字段。 除了这些预期的字段之外,我还添加了一个 user_id 字段,将该用户动态链接到其作者。 你已经看到所有用户都有一个唯一的 id 主键, 将用户动态链接到其作者的方法是添加对用户 id 的引用,这正是 user_id 字段所在的位置。 这个 user_id 字段被称为 外键 。 上面的数据库图显示了外键作为该字段和它引用的表的 id 字段之间的链接。 这种关系被称为 一对多 ,因为“一个”用户写了“多”条动态。

修改后的 app/models.py 如下:

from datetime import datetime
from app import db

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    password_hash = db.Column(db.String(128))
    posts = db.relationship('Post', backref='author', lazy='dynamic')

    def __repr__(self):
        return '<User {}>'.format(self.username)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.String(140))
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return '<Post {}>'.format(self.body)

新的“Post”类表示用户发表的动态。 timestamp 字段将被编入索引,如果你想按时间顺序检索用户动态,这将非常有用。 我还为其添加了一个 default 参数,并传入了 datetime.utcnow 函数。 当你将一个函数作为默认值传入后,SQLAlchemy 会将该字段设置为调用该函数的值(请注意,在 utcnow 之后我没有包含 () ,所以我传递函数本身,而不是调用它的结果)。 通常,在服务应用中使用 UTC 日期和时间是推荐做法。 这可以确保你使用统一的时间戳,无论用户位于何处,这些时间戳会在显示时转换为用户的当地时间。

user_id 字段被初始化为 user.id 的外键,这意味着它引用了来自用户表的 id 值。本处的 user 是数据库表的名称,Flask-SQLAlchemy 自动设置类名为小写来作为对应表的名称。 User 类有一个新的 posts 字段,用 db.relationship 初始化。这不是实际的数据库字段,而是用户和其动态之间关系的高级视图,因此它不在数据库图表中。对于一对多关系, db.relationship 字段通常在“一”的这边定义,并用作访问“多”的便捷方式。因此,如果我有一个用户实例 u ,表达式 u.posts 将运行一个数据库查询,返回该用户发表过的所有动态。 db.relationship 的第一个参数表示代表关系“多”的类。 backref 参数定义了代表“多”的类的实例反向调用“一”的时候的属性名称。这将会为用户动态添加一个属性 post.author ,调用它将返回给该用户动态的用户实例。 lazy 参数定义了这种关系调用的数据库查询是如何执行的,这个我会在后面讨论。不要觉得这些细节没什么意思,本章的结尾将会给出对应的例子。

一旦我变更了应用模型,就需要生成一个新的数据库迁移:

(venv) $ flask db migrate -m "posts table"
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'post'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_post_timestamp' on '['timestamp']'
  Generating /home/miguel/microblog/migrations/versions/780739b227a7_posts_table.py ... done

并将这个迁移应用到数据库:

(venv) $ flask db upgrade
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade e517276bb1c2 -> 780739b227a7, posts table

如果你对项目使用了版本控制,记得将新的迁移脚本添加进去并提交。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文