class documentation

class declared_attr(interfaces._MappedAttribute, property):

Known subclasses: sqlalchemy.orm.decl_api._stateful_declared_attr

View In Hierarchy

Mark a class-level method as representing the definition of a mapped property or special declarative member name.

_orm.declared_attr is typically applied as a decorator to a class level method, turning the attribute into a scalar-like property that can be invoked from the uninstantiated class. The Declarative mapping process looks for these _orm.declared_attr callables as it scans classes, and assumes any attribute marked with _orm.declared_attr will be a callable that will produce an object specific to the Declarative mapping or table configuration.

_orm.declared_attr is usually applicable to mixins, to define relationships that are to be applied to different implementors of the class. It is also used to define _schema.Column objects that include the _schema.ForeignKey construct, as these cannot be easily reused across different mappings. The example below illustrates both:

class ProvidesUser(object):
    "A mixin that adds a 'user' relationship to classes."

    @declared_attr
    def user_id(self):
        return Column(ForeignKey("user_account.id"))

    @declared_attr
    def user(self):
        return relationship("User")

_orm.declared_attr can also be applied to mapped classes, such as to provide a "polymorphic" scheme for inheritance:

class Employee(Base):
    id = Column(Integer, primary_key=True)
    type = Column(String(50), nullable=False)

    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    @declared_attr
    def __mapper_args__(cls):
        if cls.__name__ == 'Employee':
            return {
                    "polymorphic_on":cls.type,
                    "polymorphic_identity":"Employee"
            }
        else:
            return {"polymorphic_identity":cls.__name__}

To use _orm.declared_attr inside of a Python dataclass as discussed at :ref:`orm_declarative_dataclasses_declarative_table`, it may be placed directly inside the field metadata using a lambda:

@dataclass
class AddressMixin:
    __sa_dataclass_metadata_key__ = "sa"

    user_id: int = field(
        init=False, metadata={"sa": declared_attr(lambda: Column(ForeignKey("user.id")))}
    )
    user: User = field(
        init=False, metadata={"sa": declared_attr(lambda: relationship(User))}
    )

_orm.declared_attr also may be omitted from this form using a lambda directly, as in:

user: User = field(
    init=False, metadata={"sa": lambda: relationship(User)}
)

See Also

:ref:`orm_mixins_toplevel` - illustrates how to use Declarative Mixins which is the primary use case for _orm.declared_attr

:ref:`orm_declarative_dataclasses_mixin` - illustrates special forms for use with Python dataclasses

Method __get__ Undocumented
Method __init__ Undocumented
Method ​_stateful Undocumented
Instance Variable ​_cascading Undocumented
Property cascading Mark a .declared_attr as cascading.

Inherited from _MappedAttribute:

Class Variable __slots__ Undocumented
def __get__(desc, self, cls):

Undocumented

def __init__(self, fget, cascading=False):
@hybridmethod
def _stateful(cls, **kw):
_cascading =

Undocumented

@hybridproperty
cascading =

Mark a .declared_attr as cascading.

This is a special-use modifier which indicates that a column or MapperProperty-based declared attribute should be configured distinctly per mapped subclass, within a mapped-inheritance scenario.

Warning

The .declared_attr.cascading modifier has several limitations:

  • The flag only applies to the use of .declared_attr on declarative mixin classes and __abstract__ classes; it currently has no effect when used on a mapped class directly.
  • The flag only applies to normally-named attributes, e.g. not any special underscore attributes such as __tablename__. On these attributes it has no effect.
  • The flag currently does not allow further overrides down the class hierarchy; if a subclass tries to override the attribute, a warning is emitted and the overridden attribute is skipped. This is a limitation that it is hoped will be resolved at some point.

Below, both MyClass as well as MySubClass will have a distinct id Column object established:

class HasIdMixin(object):
    @declared_attr.cascading
    def id(cls):
        if has_inherited_table(cls):
            return Column(
                ForeignKey('myclass.id'), primary_key=True
            )
        else:
            return Column(Integer, primary_key=True)

class MyClass(HasIdMixin, Base):
    __tablename__ = 'myclass'
    # ...

class MySubClass(MyClass):
    ""
    # ...

The behavior of the above configuration is that MySubClass will refer to both its own id column as well as that of MyClass underneath the attribute named some_id.