SqlAlchemy 2.0 中文文档(七)(5)

简介: SqlAlchemy 2.0 中文文档(七)

SqlAlchemy 2.0 中文文档(七)(4)https://developer.aliyun.com/article/1560926


将 ORM 映射应用到现有 attrs 类

attrs 库是一个流行的第三方库,提供了类似于 dataclasses 的功能,同时提供了许多在普通 dataclasses 中找不到的附加功能。

使用 attrs 增强的类使用 @define 装饰器。此装饰器启动一个过程,用于扫描类以查找定义类行为的属性,然后使用这些属性生成方法、文档和注释。

SQLAlchemy ORM 支持使用声明式与命令式表命令式映射来映射 attrs 类。这两种风格的一般形式与数据类一起使用的使用声明式字段映射预先存在的数据类和使用声明式与命令式表映射预先存在的数据类的映射形式完全相同,其中数据类或 attrs 使用的内联属性指令保持不变,并且 SQLAlchemy 的面向表的仪器化在运行时应用。

attrs@define 装饰器默认用新的基于 slots 的类替换注释类,这是不受支持的。当使用旧式注释 @attr.s 或使用 define(slots=False) 时,类不会被替换。此外,attrs 在装饰器运行后移除了自己的类绑定属性,以便 SQLAlchemy 的映射过程接管这些属性而不会出现任何问题。@attr.s@define(slots=False) 两个装饰器都适用于 SQLAlchemy。

使用声明式“命令式表”映射属性

在“声明式与命令式表”风格中,Table 对象与声明式类内联声明。首先将 @define 装饰器应用于类,然后将 registry.mapped() 装饰器应用于第二个位置:

from __future__ import annotations
from typing import List
from typing import Optional
from attrs import define
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import registry
from sqlalchemy.orm import relationship
mapper_registry = registry()
@mapper_registry.mapped
@define(slots=False)
class User:
    __table__ = Table(
        "user",
        mapper_registry.metadata,
        Column("id", Integer, primary_key=True),
        Column("name", String(50)),
        Column("FullName", String(50), key="fullname"),
        Column("nickname", String(12)),
    )
    id: Mapped[int]
    name: Mapped[str]
    fullname: Mapped[str]
    nickname: Mapped[str]
    addresses: Mapped[List[Address]]
    __mapper_args__ = {  # type: ignore
        "properties": {
            "addresses": relationship("Address"),
        }
    }
@mapper_registry.mapped
@define(slots=False)
class Address:
    __table__ = Table(
        "address",
        mapper_registry.metadata,
        Column("id", Integer, primary_key=True),
        Column("user_id", Integer, ForeignKey("user.id")),
        Column("email_address", String(50)),
    )
    id: Mapped[int]
    user_id: Mapped[int]
    email_address: Mapped[Optional[str]]
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37
• 38
• 39
• 40
• 41
• 42
• 43
• 44
• 45
• 46
• 47
• 48
• 49
• 50
• 51
• 52
• 53
• 54

注意

attrsslots=True 选项,在映射类上启用了 __slots__,不能与未完全实现备用 属性仪器化 的 SQLAlchemy 映射一起使用,因为映射类通常依赖于直接访问 __dict__ 进行状态存储。当此选项存在时,行为是未定义的。

使用命令式映射映射属性

正如对于数据类一样,我们可以使用 registry.map_imperatively() 来映射现有的 attrs 类:

from __future__ import annotations
from typing import List
from attrs import define
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy.orm import registry
from sqlalchemy.orm import relationship
mapper_registry = registry()
@define(slots=False)
class User:
    id: int
    name: str
    fullname: str
    nickname: str
    addresses: List[Address]
@define(slots=False)
class Address:
    id: int
    user_id: int
    email_address: Optional[str]
metadata_obj = MetaData()
user = Table(
    "user",
    metadata_obj,
    Column("id", Integer, primary_key=True),
    Column("name", String(50)),
    Column("fullname", String(50)),
    Column("nickname", String(12)),
)
address = Table(
    "address",
    metadata_obj,
    Column("id", Integer, primary_key=True),
    Column("user_id", Integer, ForeignKey("user.id")),
    Column("email_address", String(50)),
)
mapper_registry.map_imperatively(
    User,
    user,
    properties={
        "addresses": relationship(Address, backref="user", order_by=address.c.id),
    },
)
mapper_registry.map_imperatively(Address, address)
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37
• 38
• 39
• 40
• 41
• 42
• 43
• 44
• 45
• 46
• 47
• 48
• 49
• 50
• 51
• 52
• 53
• 54
• 55
• 56
• 57
• 58

上述形式等同于先前使用声明式与命令式表的示例。

使用声明式“命令式表”映射属性

在“声明式与命令式表”风格中,Table 对象与声明式类内联声明。首先将 @define 装饰器应用于类,然后将 registry.mapped() 装饰器应用于第二个位置:

from __future__ import annotations
from typing import List
from typing import Optional
from attrs import define
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import registry
from sqlalchemy.orm import relationship
mapper_registry = registry()
@mapper_registry.mapped
@define(slots=False)
class User:
    __table__ = Table(
        "user",
        mapper_registry.metadata,
        Column("id", Integer, primary_key=True),
        Column("name", String(50)),
        Column("FullName", String(50), key="fullname"),
        Column("nickname", String(12)),
    )
    id: Mapped[int]
    name: Mapped[str]
    fullname: Mapped[str]
    nickname: Mapped[str]
    addresses: Mapped[List[Address]]
    __mapper_args__ = {  # type: ignore
        "properties": {
            "addresses": relationship("Address"),
        }
    }
@mapper_registry.mapped
@define(slots=False)
class Address:
    __table__ = Table(
        "address",
        mapper_registry.metadata,
        Column("id", Integer, primary_key=True),
        Column("user_id", Integer, ForeignKey("user.id")),
        Column("email_address", String(50)),
    )
    id: Mapped[int]
    user_id: Mapped[int]
    email_address: Mapped[Optional[str]]
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37
• 38
• 39
• 40
• 41
• 42
• 43
• 44
• 45
• 46
• 47
• 48
• 49
• 50
• 51
• 52
• 53
• 54

注意

attrsslots=True 选项可以在映射类上启用 __slots__,但在不完全实现替代的属性调试时,无法与 SQLAlchemy 映射一起使用,因为映射类通常依赖于直接访问 __dict__ 来存储状态。当存在此选项时,行为是未定义的。

使用命令式映射(Imperative Mapping)进行属性映射

就像在数据类中一样,我们可以利用registry.map_imperatively()来映射现有的 attrs 类:

from __future__ import annotations
from typing import List
from attrs import define
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy.orm import registry
from sqlalchemy.orm import relationship
mapper_registry = registry()
@define(slots=False)
class User:
    id: int
    name: str
    fullname: str
    nickname: str
    addresses: List[Address]
@define(slots=False)
class Address:
    id: int
    user_id: int
    email_address: Optional[str]
metadata_obj = MetaData()
user = Table(
    "user",
    metadata_obj,
    Column("id", Integer, primary_key=True),
    Column("name", String(50)),
    Column("fullname", String(50)),
    Column("nickname", String(12)),
)
address = Table(
    "address",
    metadata_obj,
    Column("id", Integer, primary_key=True),
    Column("user_id", Integer, ForeignKey("user.id")),
    Column("email_address", String(50)),
)
mapper_registry.map_imperatively(
    User,
    user,
    properties={
        "addresses": relationship(Address, backref="user", order_by=address.c.id),
    },
)
mapper_registry.map_imperatively(Address, address)
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37
• 38
• 39
• 40
• 41
• 42
• 43
• 44
• 45
• 46
• 47
• 48
• 49
• 50
• 51
• 52
• 53
• 54
• 55
• 56
• 57
• 58

上述形式等同于使用命令式表格进行声明的上一个示例。

相关文章
|
5月前
|
SQL 前端开发 数据库
SqlAlchemy 2.0 中文文档(六)(1)
SqlAlchemy 2.0 中文文档(六)
61 0
|
5月前
|
SQL 测试技术 API
SqlAlchemy 2.0 中文文档(一)(1)
SqlAlchemy 2.0 中文文档(一)
201 1
SqlAlchemy 2.0 中文文档(一)(1)
|
5月前
|
SQL JSON 关系型数据库
SqlAlchemy 2.0 中文文档(五)(5)
SqlAlchemy 2.0 中文文档(五)
64 4
|
5月前
|
SQL API 数据库
SqlAlchemy 2.0 中文文档(一)(5)
SqlAlchemy 2.0 中文文档(一)
129 1
|
5月前
|
测试技术 API 数据库
SqlAlchemy 2.0 中文文档(十)(4)
SqlAlchemy 2.0 中文文档(十)
74 1
|
5月前
|
SQL 数据库 Python
SqlAlchemy 2.0 中文文档(十)(3)
SqlAlchemy 2.0 中文文档(十)
39 1
|
5月前
|
SQL 存储 API
SqlAlchemy 2.0 中文文档(十)(5)
SqlAlchemy 2.0 中文文档(十)
35 1
|
5月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(三)(1)
SqlAlchemy 2.0 中文文档(三)
51 1
|
5月前
|
SQL 关系型数据库 测试技术
SqlAlchemy 2.0 中文文档(十)(1)
SqlAlchemy 2.0 中文文档(十)
38 1
|
5月前
|
SQL 测试技术 Python
SqlAlchemy 2.0 中文文档(二)(1)
SqlAlchemy 2.0 中文文档(二)
63 2