Skip to content

DM + SQL storage how-to#

本指南展示如何使用 RESTAlchemy 将 DM 模型持久化到 SQL 数据库。

你将学会:

  • 使用 ModelWithUUIDSQLStorableMixin 定义可持久化的 DM 模型。
  • 配置 SQL 引擎(MySQL 或 PostgreSQL)。
  • 通过 .save().delete()Model.objects 执行 CRUD 操作。
  • 使用过滤器构造查询条件。

示例基于 examples/dm_mysql_storage.pyexamples/dm_pg_storage.py


前置条件#

  • 已安装 RESTAlchemy(见 installation.md)。
  • 有一套正在运行的数据库:
  • MySQL/MariaDB,或
  • PostgreSQL。
  • 安装了对应的 Python 驱动,例如:
  • mysql-connector-python(MySQL)。
  • psycopg[binary](PostgreSQL)。
  • 数据库中已存在与模型对应的表结构(可通过迁移工具创建)。

1. 为 SQL 定义 DM 模型#

基本模式:

  • 继承自 models.ModelWithUUID(或其它 ModelWithID)。
  • 同时继承 orm.SQLStorableMixin
  • 设置 __tablename__
  • 使用 DM 属性与类型定义字段。

示例(简化自 dm_mysql_storage.py):

from restalchemy.dm import models, properties, relationships, types
from restalchemy.storage.sql import orm


class FooModel(models.ModelWithUUID, orm.SQLStorableMixin):
    __tablename__ = "foos"
    foo_field1 = properties.property(types.Integer(), required=True)
    foo_field2 = properties.property(types.String(), default="foo_str")


class BarModel(models.ModelWithUUID, orm.SQLStorableMixin):
    __tablename__ = "bars"
    bar_field1 = properties.property(types.String(min_length=1, max_length=10))
    foo = relationships.relationship(FooModel)

2. 配置 SQL 引擎#

通过 restalchemy.storage.sql.engines.engine_factory 创建引擎实例。

MySQL 示例#

from restalchemy.storage.sql import engines

engines.engine_factory.configure_factory(
    db_url="mysql://user:password@127.0.0.1:3306/test",
)

PostgreSQL 示例#

from restalchemy.storage.sql import engines

engines.engine_factory.configure_factory(
    db_url="postgresql://postgres:password@127.0.0.1:5432/ra_tests",
)

通常在应用启动时调用一次 configure_factory()。之后所有带有 SQLStorableMixin 的模型会通过 engine_factory.get_engine() 获得引擎。

可选参数:

  • config:引擎配置(连接池大小、超时等)。
  • query_cache:是否启用会话级查询缓存。

3. 创建表与迁移#

RESTAlchemy 不会自动创建数据表,而是依赖显式迁移。

迁移命令在 README.rst 中有说明:

  • ra-new-migration:创建新的迁移文件。
  • ra-apply-migration:应用迁移。

示例文件中包含以注释形式给出的 SQL 结构,例如 dm_mysql_storage.py

CREATE TABLE `foos` (
     `uuid` CHAR(36) NOT NULL,
     `foo_field1` INT NOT NULL,
     `foo_field2` VARCHAR(255) NOT NULL,
 PRIMARY KEY (`uuid`)
) ENGINE = InnoDB;

CREATE TABLE `bars` (
    `uuid` CHAR(36) NOT NULL,
    `bar_field1` VARCHAR(10) NOT NULL,
    `foo` CHAR(36) NOT NULL,
    CONSTRAINT `_idx_foo` FOREIGN KEY (`foo`) REFERENCES `foos`(`uuid`)
) ENGINE = InnoDB;

你可以按自己的环境调整这些结构,或生成产生同类 DDL 的迁移。


4. 基本 CRUD 操作#

在配置好引擎并创建表之后,可以像操作普通 DM 模型一样进行 CRUD:

创建与保存#

foo1 = FooModel(foo_field1=10)
foo1.save()

bar1 = BarModel(bar_field1="test", foo=foo1)
bar1.save()

读取数据#

# 所有 Bar
all_bars = list(BarModel.objects.get_all())

# 根据主键读取一个 Bar
same_bar = BarModel.objects.get_one(filters={"uuid": bar1.get_id()})

# 获取某个 Foo 下的所有 Bar
bars_for_foo = list(BarModel.objects.get_all(filters={"foo": foo1}))

print(bar1.as_plain_dict())

更新#

foo2 = FooModel(foo_field1=11, foo_field2="some text")
foo2.save()

foo2.foo_field2 = "updated text"
foo2.save()

删除#

for foo in FooModel.objects.get_all():
    foo.delete()

5. 过滤(Filters)#

过滤器定义在 restalchemy.dm.filters 中,可传递给 get_all()get_one()

简单过滤条件#

from restalchemy.dm import filters

one = FooModel.objects.get_one(filters={"foo_field1": filters.EQ(10)})

greater = list(
    FooModel.objects.get_all(filters={"foo_field1": filters.GT(5)})
)

subset = list(
    FooModel.objects.get_all(filters={"foo_field1": filters.In([5, 6])})
)

not_subset = list(
    FooModel.objects.get_all(filters={"foo_field1": filters.NotIn([1, 2])})
)

复杂表达式#

可以用 ANDOR 表达式构建复杂条件:

filter_expr = filters.OR(
    filters.AND({
        "foo_field1": filters.EQ(1),
        "foo_field2": filters.EQ("2"),
    }),
    filters.AND({"foo_field2": filters.EQ("3")}),
)

foo = FooModel.objects.get_one(filters=filter_expr)

6. 事务与显式会话#

默认情况下,每次操作使用独立的会话与事务。

若需要将多次操作合并到一个事务中,可以使用 engine.session_manager()

使用 engine.session_manager()#

from restalchemy.storage.sql import engines

engine = engines.engine_factory.get_engine()

with engine.session_manager() as session:
    foo = FooModel(foo_field1=42)
    foo.save(session=session)

    bar = BarModel(bar_field1="x", foo=foo)
    bar.save(session=session)
    # 如果这里发生异常,两条 INSERT 都会被回滚。

with 代码块中的所有操作共享同一个会话与事务。

你也可以把从引擎获取的会话对象复用到代码的其他位置:把 session= 传给 .save().delete() 或集合方法即可。


小结#

  • 通过 ModelWithUUID + SQLStorableMixin 定义持久化模型,并设置 __tablename__
  • 使用 engine_factory.configure_factory() 配置 SQL 引擎。
  • 使用迁移工具创建/更新数据库表。
  • 使用 .save().delete()Model.objects.get_all()/get_one() 实现 CRUD。
  • 使用 DM 过滤器表示查询条件。
  • 在需要时通过显式会话控制事务边界。