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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: SqlAlchemy 2.0 中文文档(五)

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


自定义类型映射

Python 类型到 SQLAlchemy TypeEngine类型的映射在前一节中描述的默认为sqlalchemy.sql.sqltypes模块中的硬编码字典。然而,协调 Declarative 映射过程的registry对象将首先查阅一个本地的、用户定义的类型字典,该字典可以在构建registry时作为registry.type_annotation_map参数传递,当首次使用时可能与DeclarativeBase超类相关联。

举例来说,如果我们希望使用BIGINT数据类型来表示int,使用带有timezone=TrueTIMESTAMP数据类型来表示datetime.datetime,然后仅在 Microsoft SQL Server 上使用NVARCHAR数据类型来表示 Python 的str,则可以配置注册表和 Declarative 基类如下:

import datetime
from sqlalchemy import BIGINT, Integer, NVARCHAR, String, TIMESTAMP
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped, mapped_column, registry
class Base(DeclarativeBase):
    type_annotation_map = {
        int: BIGINT,
        datetime.datetime: TIMESTAMP(timezone=True),
        str: String().with_variant(NVARCHAR, "mssql"),
    }
class SomeClass(Base):
    __tablename__ = "some_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    date: Mapped[datetime.datetime]
    status: Mapped[str]

下面展示了为上述映射生成的 CREATE TABLE 语句,在 Microsoft SQL Server 后端首先展示了NVARCHAR数据类型:

>>> from sqlalchemy.schema import CreateTable
>>> from sqlalchemy.dialects import mssql, postgresql
>>> print(CreateTable(SomeClass.__table__).compile(dialect=mssql.dialect()))
CREATE  TABLE  some_table  (
  id  BIGINT  NOT  NULL  IDENTITY,
  date  TIMESTAMP  NOT  NULL,
  status  NVARCHAR(max)  NOT  NULL,
  PRIMARY  KEY  (id)
) 

然后在 PostgreSQL 后端,展示了TIMESTAMP WITH TIME ZONE

>>> print(CreateTable(SomeClass.__table__).compile(dialect=postgresql.dialect()))
CREATE  TABLE  some_table  (
  id  BIGSERIAL  NOT  NULL,
  date  TIMESTAMP  WITH  TIME  ZONE  NOT  NULL,
  status  VARCHAR  NOT  NULL,
  PRIMARY  KEY  (id)
) 

通过使用诸如TypeEngine.with_variant()之类的方法,我们能够构建一个针对不同后端定制的类型映射,同时仍然能够使用简洁的仅注释的mapped_column()配置。在此之上还有两个级别的 Python 类型可配置性,将在接下来的两个部分中描述。

将多种类型配置映射到 Python 类型

由于个别 Python 类型可以通过使用TypeEngine配置的任何类型与registry.type_annotation_map参数相关联,另一个功能是能够将单个 Python 类型与基于附加类型限定符的 SQL 类型的不同变体关联起来。一个典型的例子是将 Python 的str数据类型映射到不同长度的VARCHAR SQL 类型。另一个是将不同种类的decimal.Decimal映射到不同大小的NUMERIC列。

Python 的类型系统提供了一种很好的方式来为 Python 类型添加额外的元数据,即使用PEP 593 Annotated泛型类型,它允许将附加信息与 Python 类型捆绑在一起。mapped_column()构造将正确解释Annotated对象的身份,当在registry.type_annotation_map中解析它时,就像下面的示例中声明两个StringNumeric变体一样:

from decimal import Decimal
from typing_extensions import Annotated
from sqlalchemy import Numeric
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import registry
str_30 = Annotated[str, 30]
str_50 = Annotated[str, 50]
num_12_4 = Annotated[Decimal, 12]
num_6_2 = Annotated[Decimal, 6]
class Base(DeclarativeBase):
    registry = registry(
        type_annotation_map={
            str_30: String(30),
            str_50: String(50),
            num_12_4: Numeric(12, 4),
            num_6_2: Numeric(6, 2),
        }
    )

在上述示例中传递给Annotated容器的 Python 类型,例如strDecimal类型,仅对于类型工具的好处是重要的;就mapped_column()构造而言,在这个特定的上下文中,它只需要在registry.type_annotation_map字典中查找每个类型对象,而不实际查看Annotated对象的内部。类似地,传递给Annotated的参数超出底层 Python 类型本身也不重要,只是必须至少存在一个参数,以使Annotated构造有效。然后,我们可以直接在我们的映射中使用这些增强类型,它们将与更具体的类型构造相匹配,就像以下示例中一样:

class SomeClass(Base):
    __tablename__ = "some_table"
    short_name: Mapped[str_30] = mapped_column(primary_key=True)
    long_name: Mapped[str_50]
    num_value: Mapped[num_12_4]
    short_num_value: Mapped[num_6_2]

上述映射的 CREATE TABLE 将说明我们配置的不同变体的VARCHARNUMERIC,并且看起来像是:

>>> from sqlalchemy.schema import CreateTable
>>> print(CreateTable(SomeClass.__table__))
CREATE  TABLE  some_table  (
  short_name  VARCHAR(30)  NOT  NULL,
  long_name  VARCHAR(50)  NOT  NULL,
  num_value  NUMERIC(12,  4)  NOT  NULL,
  short_num_value  NUMERIC(6,  2)  NOT  NULL,
  PRIMARY  KEY  (short_name)
) 

虽然将Annotated类型与不同的 SQL 类型链接的多样性为我们提供了广泛的灵活性,但下一节说明了一种使用Annotated与 Declarative 结合使用的第二种更加开放的方式。

将整个列声明映射到 Python 类型

前面的章节说明了使用PEP 593 Annotated类型实例作为registry.type_annotation_map字典中的键。在这种形式中,mapped_column()构造实际上并不查看Annotated对象本身,而是仅用作字典键。然而,Declarative 还具有直接从Annotated对象中提取整个预先建立的mapped_column()构造的能力。使用这种形式,我们不仅可以定义与 Python 类型相关联的不同种类的 SQL 数据类型,而且还可以以可重用的方式设置任意数量的参数,例如可为空性、列默认值和约束。

一组 ORM 模型通常会有一种对所有映射类都通用的主键样式。还可能有常见的列配置,例如具有默认值的时间戳和其他预先确定大小和配置的字段。我们可以将这些配置组合成mapped_column()实例,然后直接捆绑到Annotated的实例中,然后在任意数量的类声明中重复使用。当以这种方式提供时,声明性将解开Annotated对象,跳过任何不适用于 SQLAlchemy 的其他指令,并仅搜索 SQLAlchemy ORM 构造。

下面的示例说明了以这种方式使用的各种预配置字段类型,其中我们定义了intpk代表一个整型主键列,timestamp代表一个日期时间类型,它将使用CURRENT_TIMESTAMP作为 DDL 级别的列默认值,并且required_name是一个长度为 30 的字符串,它是NOT NULL的:

import datetime
from typing_extensions import Annotated
from sqlalchemy import func
from sqlalchemy import String
from sqlalchemy.orm import mapped_column
intpk = Annotated[int, mapped_column(primary_key=True)]
timestamp = Annotated[
    datetime.datetime,
    mapped_column(nullable=False, server_default=func.CURRENT_TIMESTAMP()),
]
required_name = Annotated[str, mapped_column(String(30), nullable=False)]

上述的Annotated对象然后可以直接在Mapped中使用,预配置的mapped_column()构造将被提取并复制到一个新实例中,该实例将针对每个属性具体:

class Base(DeclarativeBase):
    pass
class SomeClass(Base):
    __tablename__ = "some_table"
    id: Mapped[intpk]
    name: Mapped[required_name]
    created_at: Mapped[timestamp]

我们上面的映射的CREATE TABLE如下所示:

>>> from sqlalchemy.schema import CreateTable
>>> print(CreateTable(SomeClass.__table__))
CREATE  TABLE  some_table  (
  id  INTEGER  NOT  NULL,
  name  VARCHAR(30)  NOT  NULL,
  created_at  DATETIME  DEFAULT  CURRENT_TIMESTAMP  NOT  NULL,
  PRIMARY  KEY  (id)
) 

当以这种方式使用Annotated类型时,类型的配置也可能会受到每个属性基础的影响。对于上面示例中显式使用了mapped_column.nullable的类型,我们可以对我们的任何类型应用Optional[]泛型修饰符,以便在 Python 级别该字段是可选的还是不可选的,这将独立于数据库中发生的NULL / NOT NULL设置:

from typing_extensions import Annotated
import datetime
from typing import Optional
from sqlalchemy.orm import DeclarativeBase
timestamp = Annotated[
    datetime.datetime,
    mapped_column(nullable=False),
]
class Base(DeclarativeBase):
    pass
class SomeClass(Base):
    # ...
    # pep-484 type will be Optional, but column will be
    # NOT NULL
    created_at: Mapped[Optional[timestamp]]

mapped_column()构造还与显式传递的mapped_column()构造协调一致,其参数将优先于Annotated构造的参数。下面我们向我们的整型主键添加了一个外键约束,并且还为created_at列使用了备用服务器默认值:

import datetime
from typing_extensions import Annotated
from sqlalchemy import ForeignKey
from sqlalchemy import func
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.schema import CreateTable
intpk = Annotated[int, mapped_column(primary_key=True)]
timestamp = Annotated[
    datetime.datetime,
    mapped_column(nullable=False, server_default=func.CURRENT_TIMESTAMP()),
]
class Base(DeclarativeBase):
    pass
class Parent(Base):
    __tablename__ = "parent"
    id: Mapped[intpk]
class SomeClass(Base):
    __tablename__ = "some_table"
    # add ForeignKey to mapped_column(Integer, primary_key=True)
    id: Mapped[intpk] = mapped_column(ForeignKey("parent.id"))
    # change server default from CURRENT_TIMESTAMP to UTC_TIMESTAMP
    created_at: Mapped[timestamp] = mapped_column(server_default=func.UTC_TIMESTAMP())

CREATE TABLE语句说明了这些每个属性的设置,添加了FOREIGN KEY约束,并且将UTC_TIMESTAMP替换为CURRENT_TIMESTAMP

>>> from sqlalchemy.schema import CreateTable
>>> print(CreateTable(SomeClass.__table__))
CREATE  TABLE  some_table  (
  id  INTEGER  NOT  NULL,
  created_at  DATETIME  DEFAULT  UTC_TIMESTAMP()  NOT  NULL,
  PRIMARY  KEY  (id),
  FOREIGN  KEY(id)  REFERENCES  parent  (id)
) 

注意

刚刚描述的 mapped_column() 特性,其中可以使用 PEP 593 Annotated 对象指示一组完全构造的列参数,这些列参数包含一个“模板” mapped_column() 对象,将被复制到属性中,目前尚未实现为其他 ORM 构造(如 relationship()composite())。虽然理论上可能存在这种功能,但目前尝试使用 Annotated 来指示 relationship() 等的进一步参数将在运行时引发 NotImplementedError 异常,但可能会在将来的版本中实现。

在类型映射中使用 Python Enum 或 pep-586 Literal 类型

新版本 2.0.0b4 中新增:- 添加了 Enum 支持

新版本 2.0.1 中新增:- 添加了 Literal 支持

当在 ORM 声明性映射中使用用户定义的 Python 类型时,这些类型派生自 Python 内置的 enum.Enum 类以及 typing.Literal 类时,它们会自动链接到 SQLAlchemy Enum 数据类型。下面的示例在 Mapped[] 构造函数中使用了自定义的 enum.Enum

import enum
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
    pass
class Status(enum.Enum):
    PENDING = "pending"
    RECEIVED = "received"
    COMPLETED = "completed"
class SomeClass(Base):
    __tablename__ = "some_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    status: Mapped[Status]

在上面的示例中,映射的属性 SomeClass.status 将链接到一个 Column,其数据类型为 Enum(Status)。我们可以在 PostgreSQL 数据库的 CREATE TABLE 输出中看到这一点:

CREATE  TYPE  status  AS  ENUM  ('PENDING',  'RECEIVED',  'COMPLETED')
CREATE  TABLE  some_table  (
  id  SERIAL  NOT  NULL,
  status  status  NOT  NULL,
  PRIMARY  KEY  (id)
)

类似地,也可以使用 typing.Literal,使用包含所有字符串的 typing.Literal

from typing import Literal
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
    pass
Status = Literal["pending", "received", "completed"]
class SomeClass(Base):
    __tablename__ = "some_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    status: Mapped[Status]

registry.type_annotation_map 中使用的条目将基本的 enum.Enum Python 类型以及 typing.Literal 类型链接到 SQLAlchemy Enum SQL 类型,使用特殊形式来指示 Enum 数据类型应自动配置自己以针对任意枚举类型。默认情况下,此配置是隐式的,但可以显式指示为:

import enum
import typing
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
    type_annotation_map = {
        enum.Enum: sqlalchemy.Enum(enum.Enum),
        typing.Literal: sqlalchemy.Enum(enum.Enum),
    }

在 Declarative 内部的解析逻辑能够解析enum.Enum的子类以及typing.Literal的实例,以匹配registry.type_annotation_map字典中的enum.Enumtyping.Literal条目。然后,Enum SQL 类型知道如何生成具有适当设置的已配置版本,包括默认字符串长度。如果传递的typing.Literal不仅由字符串值组成,则会引发信息性错误。

本地枚举和命名

Enum.native_enum参数是指Enum数据类型是否应创建所谓的“本地”枚举,在 MySQL/MariaDB 上是ENUM数据类型,在 PostgreSQL 上是通过CREATE TYPE创建的新TYPE对象,或者是“非本地”枚举,这意味着将使用VARCHAR创建数据类型。对于 MySQL/MariaDB 或 PostgreSQL 以外的后端,在所有情况下都使用VARCHAR(第三方方言可能具有自己的行为)。

因为 PostgreSQL 的CREATE TYPE要求为要创建的类型指定显式名称,所以在处理未显式指定显式Enum数据类型的情况下,特殊的后备逻辑存在于隐式生成的Enum时:

  1. 如果Enum链接到一个enum.Enum对象,则Enum.native_enum参数默认为True,并且枚举的名称将取自enum.Enum数据类型的名称。 PostgreSQL 后端将假定使用此名称创建CREATE TYPE
  2. 如果Enum链接到一个typing.Literal对象,则Enum.native_enum参数默认为False;不会生成名称,并且假定为VARCHAR

要在 PostgreSQL 的CREATE TYPE类型中使用typing.Literal,必须使用显式的Enum,要么在类型映射中:

import enum
import typing
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
Status = Literal["pending", "received", "completed"]
class Base(DeclarativeBase):
    type_annotation_map = {
        Status: sqlalchemy.Enum("pending", "received", "completed", name="status_enum"),
    }

或者在 mapped_column() 内部:

import enum
import typing
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
Status = Literal["pending", "received", "completed"]
class Base(DeclarativeBase):
    pass
class SomeClass(Base):
    __tablename__ = "some_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    status: Mapped[Status] = mapped_column(
        sqlalchemy.Enum("pending", "received", "completed", name="status_enum")
    )
修改默认枚举的配置

为了修改隐式生成的Enum数据类型的固定配置,指定在registry.type_annotation_map中添加新条目,表示额外参数。例如,要无条件使用“非原生枚举”,可以为所有类型设置Enum.native_enum参数为 False:

import enum
import typing
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
    type_annotation_map = {
        enum.Enum: sqlalchemy.Enum(enum.Enum, native_enum=False),
        typing.Literal: sqlalchemy.Enum(enum.Enum, native_enum=False),
    }

从 2.0.1 版本开始更改:实现了在建立registry.type_annotation_map时覆盖参数的支持,例如Enum.native_enum参数。以前,此功能未能正常工作。

要为特定的enum.Enum子类型使用特定的配置,例如在使用示例Status数据类型时将字符串长度设置为 50:

import enum
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
class Status(enum.Enum):
    PENDING = "pending"
    RECEIVED = "received"
    COMPLETED = "completed"
class Base(DeclarativeBase):
    type_annotation_map = {
        Status: sqlalchemy.Enum(Status, length=50, native_enum=False)
    }

默认情况下,自动生成的Enum不与由Base使用的MetaData实例关联,因此,如果元数据定义了模式,它将不会自动与枚举关联。要将枚举自动与元数据或表中的模式关联起来,可以设置Enum.inherit_schema

from enum import Enum
import sqlalchemy as sa
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
    metadata = sa.MetaData(schema="my_schema")
    type_annotation_map = {Enum: sa.Enum(Enum, inherit_schema=True)}
将特定的enum.Enumtyping.Literal链接到其他数据类型

以上示例展示了一个Enum自动配置自身到一个enum.Enumtyping.Literal类型对象上存在的参数/属性的情况。对于应用场景,特定类型的enum.Enumtyping.Literal应链接到其他类型的情况,这些特定类型也可以放置在类型映射中。在下面的示例中,一个包含非字符串类型的Literal[]条目被链接到JSON数据类型:

from typing import Literal
from sqlalchemy import JSON
from sqlalchemy.orm import DeclarativeBase
my_literal = Literal[0, 1, True, False, "true", "false"]
class Base(DeclarativeBase):
    type_annotation_map = {my_literal: JSON}

在上述配置中,my_literal数据类型将解析为一个JSON实例。其他Literal变体将继续解析为Enum数据类型。

原生枚举和命名

Enum.native_enum 参数指的是 Enum 数据类型是否应该创建所谓的“本地”枚举,在 MySQL/MariaDB 中是 ENUM 数据类型,在 PostgreSQL 中是由 CREATE TYPE 创建的新 TYPE 对象,或者是“非本地”枚举,这意味着将使用 VARCHAR 来创建数据类型。对于不是 MySQL/MariaDB 或 PostgreSQL 的后端,VARCHAR 在所有情况下都会被使用(第三方方言可能具有自己的行为)。

因为 PostgreSQL 的 CREATE TYPE 要求有一个明确的类型名称要被创建,所以在使用隐式生成的 Enum 时,当没有指定显式的 Enum 数据类型时,存在特殊的回退逻辑:

  1. 如果 Enumenum.Enum 对象关联,则 Enum.native_enum 参数默认为 True,并且枚举的名称将从 enum.Enum 数据类型的名称中获取。PostgreSQL 后端将假定使用此名称创建 CREATE TYPE
  2. 如果 Enumtyping.Literal 对象关联,则 Enum.native_enum 参数默认为 False;不会生成名称,假定为 VARCHAR

要在 PostgreSQL 的 CREATE TYPE 类型中使用 typing.Literal,必须使用显式的 Enum,要么在类型映射中:

import enum
import typing
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
Status = Literal["pending", "received", "completed"]
class Base(DeclarativeBase):
    type_annotation_map = {
        Status: sqlalchemy.Enum("pending", "received", "completed", name="status_enum"),
    }

或者在 mapped_column() 中:

import enum
import typing
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
Status = Literal["pending", "received", "completed"]
class Base(DeclarativeBase):
    pass
class SomeClass(Base):
    __tablename__ = "some_table"
    id: Mapped[int] = mapped_column(primary_key=True)
    status: Mapped[Status] = mapped_column(
        sqlalchemy.Enum("pending", "received", "completed", name="status_enum")
    )
修改默认枚举的配置

为了修改隐式生成的 Enum 数据类型的固定配置,可以在 registry.type_annotation_map 中指定新的条目,指示额外的参数。例如,要无条件地使用“非本地枚举”,可以为所有类型将 Enum.native_enum 参数设置为 False:

import enum
import typing
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
    type_annotation_map = {
        enum.Enum: sqlalchemy.Enum(enum.Enum, native_enum=False),
        typing.Literal: sqlalchemy.Enum(enum.Enum, native_enum=False),
    }

在 2.0.1 版本中更改:实现了在建立 registry.type_annotation_map 时重写参数的支持,例如 Enum.native_enum 中的参数。之前,此功能未正常工作。

若要针对特定的 enum.Enum 子类型使用特定配置,例如在使用示例 Status 数据类型时将字符串长度设置为 50:

import enum
import sqlalchemy
from sqlalchemy.orm import DeclarativeBase
class Status(enum.Enum):
    PENDING = "pending"
    RECEIVED = "received"
    COMPLETED = "completed"
class Base(DeclarativeBase):
    type_annotation_map = {
        Status: sqlalchemy.Enum(Status, length=50, native_enum=False)
    }

默认情况下,自动生成的 EnumBase 使用的 MetaData 实例不关联,因此如果元数据定义了模式,则不会自动将其与枚举关联起来。要将枚举自动关联到元数据或表中的模式,可以设置 Enum.inherit_schema

from enum import Enum
import sqlalchemy as sa
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
    metadata = sa.MetaData(schema="my_schema")
    type_annotation_map = {Enum: sa.Enum(Enum, inherit_schema=True)}
将特定的 enum.Enumtyping.Literal 链接到其他数据类型

上述示例展示了自动将 Enum 配置到 enum.Enumtyping.Literal 类型对象上的用法。对于应该与其他类型链接的特定种类的 enum.Enumtyping.Literal 的用例,也可以将这些特定类型放入类型映射中。在下面的示例中,包含非字符串类型的 Literal[] 条目被链接到 JSON 数据类型:

from typing import Literal
from sqlalchemy import JSON
from sqlalchemy.orm import DeclarativeBase
my_literal = Literal[0, 1, True, False, "true", "false"]
class Base(DeclarativeBase):
    type_annotation_map = {my_literal: JSON}

在上述配置中,my_literal 数据类型将解析为 JSON 实例。其他 Literal 变体将继续解析为 Enum 数据类型。

mapped_column() 中的数据类特性

mapped_column() 构造与 SQLAlchemy 的“原生数据类”功能集成,该功能在声明式数据类映射中讨论。请参阅该部分了解关于 mapped_column() 支持的其他指令的当前背景。

访问表和元数据

声明式映射的类将始终包括一个名为 __table__ 的属性;当使用 __tablename__ 进行上述配置时,声明过程通过 __table__ 属性使 Table 可用:

# access the Table
user_table = User.__table__

上述表最终与Mapper.local_table属性相同,我们可以通过运行时检查系统来查看它:

from sqlalchemy import inspect
user_table = inspect(User).local_table

与声明式registry以及基类关联的MetaData集合通常是必要的,以便执行诸如 CREATE 之类的 DDL 操作,以及与诸如 Alembic 之类的迁移工具一起使用。该对象可通过registry以及声明式基类的.metadata属性获得。下面,对于一个小脚本,我们可能希望针对 SQLite 数据库发出所有表的 CREATE:

engine = create_engine("sqlite://")
Base.metadata.create_all(engine)

声明式表配置

在使用具有__tablename__声明类属性的声明式表配置时,应该使用__table_args__声明类属性提供额外的参数供Table构造函数使用。

此属性同时适用于通常发送到Table构造函数的位置参数和关键字参数。该属性可以以两种形式之一指定。一种是作为字典:

class MyClass(Base):
    __tablename__ = "sometable"
    __table_args__ = {"mysql_engine": "InnoDB"}

另一种是元组,其中每个参数都是位置参数(通常是约束):

class MyClass(Base):
    __tablename__ = "sometable"
    __table_args__ = (
        ForeignKeyConstraint(["id"], ["remote_table.id"]),
        UniqueConstraint("foo"),
    )

关键字参数可以通过指定最后一个参数为字典的形式来指定:

class MyClass(Base):
    __tablename__ = "sometable"
    __table_args__ = (
        ForeignKeyConstraint(["id"], ["remote_table.id"]),
        UniqueConstraint("foo"),
        {"autoload": True},
    )

类还可以使用declared_attr()方法装饰器以动态方式指定__table_args__声明属性以及__tablename__属性。有关背景信息,请参阅使用混合组合映射层次结构。


相关文章
|
4月前
|
SQL 存储 API
SqlAlchemy 2.0 中文文档(四)(3)
SqlAlchemy 2.0 中文文档(四)
44 3
|
4月前
|
SQL 存储 数据库
SqlAlchemy 2.0 中文文档(一)(3)
SqlAlchemy 2.0 中文文档(一)
74 1
|
4月前
|
SQL 数据库 数据库管理
SqlAlchemy 2.0 中文文档(一)(2)
SqlAlchemy 2.0 中文文档(一)
131 1
|
4月前
|
测试技术 API 数据库
SqlAlchemy 2.0 中文文档(十)(4)
SqlAlchemy 2.0 中文文档(十)
64 1
|
4月前
|
SQL 数据库 Python
SqlAlchemy 2.0 中文文档(十)(3)
SqlAlchemy 2.0 中文文档(十)
36 1
|
4月前
|
SQL API 数据库
SqlAlchemy 2.0 中文文档(四)(1)
SqlAlchemy 2.0 中文文档(四)
40 1
|
4月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(三)(1)
SqlAlchemy 2.0 中文文档(三)
41 1
|
4月前
|
存储 Python
SqlAlchemy 2.0 中文文档(七)(5)
SqlAlchemy 2.0 中文文档(七)
26 1
|
4月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(五)(1)
SqlAlchemy 2.0 中文文档(五)
45 0
|
4月前
|
SQL 测试技术 数据库
SqlAlchemy 2.0 中文文档(三)(5)
SqlAlchemy 2.0 中文文档(三)
33 0