From: Mike Bayer Date: Fri, 24 Feb 2023 04:52:31 +0000 (-0500) Subject: use Column for legacy dataclasses mapping X-Git-Tag: rel_2_0_5~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b108297d075ae68178cd18a9cb4d06feee7e075;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git use Column for legacy dataclasses mapping Fixes: #9361 Change-Id: I9c433960664aa2b75cd03925d9dcf2e1ff27d8ce --- diff --git a/doc/build/orm/dataclasses.rst b/doc/build/orm/dataclasses.rst index 4bb74cbb22..254959ab6c 100644 --- a/doc/build/orm/dataclasses.rst +++ b/doc/build/orm/dataclasses.rst @@ -521,22 +521,16 @@ both for mapped classes as well as mixins that extend from .. _orm_declarative_dataclasses: -Applying ORM Mappings to an existing dataclass ----------------------------------------------- +Applying ORM Mappings to an existing dataclass (legacy dataclass use) +--------------------------------------------------------------------- -SQLAlchemy's :ref:`native dataclass ` -support builds upon the previous version of the feature first introduced in -SQLAlchemy 1.4, which supports the application of ORM mappings to a class after -it has been processed with the ``@dataclass`` decorator, by using either the -:meth:`_orm.registry.mapped` class decorator, or the -:meth:`_orm.registry.map_imperatively` method to apply ORM mappings to the -class using Imperative. This approach is still viable for applications that are -using partially or fully imperative mapping forms with dataclasses. +.. legacy:: -For fully Declarative mapping combined with dataclasses, the -:ref:`orm_declarative_native_dataclasses` approach should be preferred. - -.. versionadded:: 1.4 Added support for direct mapping of Python dataclasses + The approaches described here are superseded by + the :ref:`orm_declarative_native_dataclasses` feature new in the 2.0 + series of SQLAlchemy. This newer version of the feature builds upon + the dataclass support first added in version 1.4, which is described + in this section. To map an existing dataclass, SQLAlchemy's "inline" declarative directives cannot be used directly; ORM directives are assigned using one of three @@ -572,8 +566,8 @@ for all the other methods that dataclasses generates such as .. _orm_declarative_dataclasses_imperative_table: -Mapping dataclasses using Declarative With Imperative Table -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Mapping pre-existing dataclasses using Declarative With Imperative Table +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ An example of a mapping using ``@dataclass`` using :ref:`orm_imperative_table_configuration` is below. A complete @@ -650,14 +644,18 @@ approach is in the next example. .. _orm_declarative_dataclasses_declarative_table: -Mapping dataclasses using Declarative Mapping -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Mapping pre-existing dataclasses using Declarative-style fields +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. deprecated:: 2.0 This approach to Declarative mapping with +.. legacy:: This approach to Declarative mapping with dataclasses should be considered as legacy. It will remain supported however is unlikely to offer any advantages against the new approach detailed at :ref:`orm_declarative_native_dataclasses`. + Note that **mapped_column() is not supported with this use**; + the :class:`_schema.Column` construct should continue to be used to declare + table metadata within the ``metadata`` field of ``dataclasses.field()``. + The fully declarative approach requires that :class:`_schema.Column` objects are declared as class attributes, which when using dataclasses would conflict with the dataclass-level attributes. An approach to combine these together @@ -686,12 +684,10 @@ association:: __tablename__ = "user" __sa_dataclass_metadata_key__ = "sa" - id: int = field( - init=False, metadata={"sa": mapped_column(Integer, primary_key=True)} - ) - name: str = field(default=None, metadata={"sa": mapped_column(String(50))}) - fullname: str = field(default=None, metadata={"sa": mapped_column(String(50))}) - nickname: str = field(default=None, metadata={"sa": mapped_column(String(12))}) + id: int = field(init=False, metadata={"sa": Column(Integer, primary_key=True)}) + name: str = field(default=None, metadata={"sa": Column(String(50))}) + fullname: str = field(default=None, metadata={"sa": Column(String(50))}) + nickname: str = field(default=None, metadata={"sa": Column(String(12))}) addresses: List[Address] = field( default_factory=list, metadata={"sa": relationship("Address")} ) @@ -702,18 +698,14 @@ association:: class Address: __tablename__ = "address" __sa_dataclass_metadata_key__ = "sa" - id: int = field( - init=False, metadata={"sa": mapped_column(Integer, primary_key=True)} - ) - user_id: int = field( - init=False, metadata={"sa": mapped_column(ForeignKey("user.id"))} - ) - email_address: str = field(default=None, metadata={"sa": mapped_column(String(50))}) + id: int = field(init=False, metadata={"sa": Column(Integer, primary_key=True)}) + user_id: int = field(init=False, metadata={"sa": Column(ForeignKey("user.id"))}) + email_address: str = field(default=None, metadata={"sa": Column(String(50))}) .. _orm_declarative_dataclasses_mixin: -Using Declarative Mixins with Dataclasses -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Using Declarative Mixins with pre-existing dataclasses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In the section :ref:`orm_mixins_toplevel`, Declarative Mixin classes are introduced. One requirement of declarative mixins is that certain @@ -724,7 +716,7 @@ example at :ref:`orm_declarative_mixins_relationships`:: class RefTargetMixin: @declared_attr def target_id(cls): - return mapped_column("target_id", ForeignKey("target.id")) + return Column("target_id", ForeignKey("target.id")) @declared_attr def target(cls): @@ -742,9 +734,7 @@ came from a mixin that is itself a dataclass, the form would be:: __sa_dataclass_metadata_key__ = "sa" - id: int = field( - init=False, metadata={"sa": mapped_column(Integer, primary_key=True)} - ) + id: int = field(init=False, metadata={"sa": Column(Integer, primary_key=True)}) addresses: List[Address] = field( default_factory=list, metadata={"sa": lambda: relationship("Address")} @@ -755,13 +745,11 @@ came from a mixin that is itself a dataclass, the form would be:: class AddressMixin: __tablename__ = "address" __sa_dataclass_metadata_key__ = "sa" - id: int = field( - init=False, metadata={"sa": mapped_column(Integer, primary_key=True)} - ) + id: int = field(init=False, metadata={"sa": Column(Integer, primary_key=True)}) user_id: int = field( - init=False, metadata={"sa": lambda: mapped_column(ForeignKey("user.id"))} + init=False, metadata={"sa": lambda: Column(ForeignKey("user.id"))} ) - email_address: str = field(default=None, metadata={"sa": mapped_column(String(50))}) + email_address: str = field(default=None, metadata={"sa": Column(String(50))}) @mapper_registry.mapped @@ -782,8 +770,8 @@ came from a mixin that is itself a dataclass, the form would be:: .. _orm_imperative_dataclasses: -Mapping dataclasses using Imperative Mapping -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Mapping pre-existing dataclasses using Imperative Mapping +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As described previously, a class which is set up as a dataclass using the ``@dataclass`` decorator can then be further decorated using the