undefined class may also be specified either as Python functions, or more
commonly as strings. For most of these
arguments except that of the main argument, string inputs are
-**evaluated as Python expressions using Python's built-in eval() function.**,
+**evaluated as Python expressions using Python's built-in eval() function**,
as they are intended to recieve complete SQL expressions.
.. warning:: As the Python ``eval()`` function is used to interpret the
Late-Evaluation for a many-to-many relationship
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Many-to-many relationships include a reference to an additional, non-mapped
+Many-to-many relationships include a reference to an additional, typically non-mapped
:class:`_schema.Table` object that is typically present in the :class:`_schema.MetaData`
collection referred towards by the :class:`_orm.registry`. The late-evaluation
-system includes support for having this attribute also be specified as a
+system also includes support for having this attribute be specified as a
string argument which will be resolved from this :class:`_schema.MetaData`
collection. Below we specify an association table ``keyword_author``,
sharing the :class:`_schema.MetaData` collection associated with our
before the other, we can refer to the remote class using its string name.
This functionality also extends into the area of other arguments specified
on the :func:`_orm.relationship` such as the "primary join" and "order by"
- arguments. See the next section for details on this.
+ arguments. See the section :ref:`orm_declarative_relationship_eval` for
+ details on this.
.. _orm_declarative_mapper_options:
:func:`~sqlalchemy.orm.relationship` definitions which require explicit
primaryjoin, order_by etc. expressions should in all but the most
simplistic cases use **late bound** forms
-for these arguments, meaning, using either the string form or a lambda.
+for these arguments, meaning, using either the string form or a function/lambda.
The reason for this is that the related :class:`_schema.Column` objects which are to
be configured using ``@declared_attr`` are not available to another
``@declared_attr`` attribute; while the methods will work and return new
be tailored specifically to the target subclass. An example is when
constructing multiple :func:`.association_proxy` attributes which each
target a different type of child object. Below is an
-:func:`.association_proxy` / mixin example which provides a scalar list of
+:func:`.association_proxy` mixin example which provides a scalar list of
string values to an implementing class::
from sqlalchemy import Column, Integer, ForeignKey, String
Configuring Many-to-Many Relationships
======================================
-this section is moved to :ref:`orm_declarative_relationship_secondary_eval`.
+This section is moved to :ref:`orm_declarative_relationship_secondary_eval`.
In "classical" form, the table metadata is created separately with the
:class:`_schema.Table` construct, then associated with the ``User`` class via
-the :func:`.mapper` function::
+the :meth:`_orm.registry.map_imperatively` method::
from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import registry
class is passed directly as the
:paramref:`_orm.registry.map_imperatively.class_` argument.
-the table, or other from clause object
+The table, or other from clause object
--------------------------------------
In the vast majority of common cases this is an instance of
The :class:`_orm.registry` applies a default constructor, i.e. ``__init__``
method, to all mapped classes that don't explicitly have their own
``__init__`` method. The behavior of this method is such that it provides
-a convenient keyword constructor that will accept as keywords the attributes
-that are named. E.g.::
+a convenient keyword constructor that will accept as optional keyword arguments
+all the attributes that are named. E.g.::
from sqlalchemy.orm import declarative_base
class MovedIn20Warning(RemovedIn20Warning):
- """subtype of RemovedIn20Warning to indicate an API that moved only."""
+ """Subtype of RemovedIn20Warning to indicate an API that moved only."""
class SAPendingDeprecationWarning(PendingDeprecationWarning):
"""
+ if bind is not None:
+ # util.deprecated_params does not work
+ util.warn_deprecated_20(
+ 'The "bind" argument to declarative_base is'
+ "deprecated and will be removed in SQLAlchemy 2.0.",
+ )
+
return registry(
- bind=bind,
+ _bind=bind,
metadata=metadata,
class_registry=class_registry,
constructor=constructor,
def __init__(
self,
- bind=None,
metadata=None,
class_registry=None,
constructor=_declarative_constructor,
+ _bind=None,
):
r"""Construct a new :class:`_orm.registry`
to share the same registry of class names for simplified
inter-base relationships.
- :param bind: An optional
- :class:`~sqlalchemy.engine.Connectable`, will be assigned
- the ``bind`` attribute on the :class:`~sqlalchemy.schema.MetaData`
- instance.
-
- .. deprecated:: 1.4 The "bind" argument to registry is
- deprecated and will be removed in SQLAlchemy 2.0.
-
-
"""
lcl_metadata = metadata or MetaData()
- if bind:
- lcl_metadata.bind = bind
+ if _bind:
+ lcl_metadata.bind = _bind
if class_registry is None:
class_registry = weakref.WeakValueDictionary()
return _mapper(self, class_, local_table, kw)
+@util.deprecated_params(
+ bind=(
+ "2.0",
+ 'The "bind" argument to declarative_base is'
+ "deprecated and will be removed in SQLAlchemy 2.0.",
+ )
+)
def as_declarative(**kw):
"""
Class decorator which will adapt a given class into a
)
return registry(
- bind=bind, metadata=metadata, class_registry=class_registry
+ _bind=bind, metadata=metadata, class_registry=class_registry
).as_declarative_base(**kw)
from sqlalchemy import text
from sqlalchemy import true
from sqlalchemy.orm import aliased
+from sqlalchemy.orm import as_declarative
from sqlalchemy.orm import attributes
from sqlalchemy.orm import collections
from sqlalchemy.orm import column_property
from sqlalchemy.orm import contains_alias
from sqlalchemy.orm import contains_eager
from sqlalchemy.orm import create_session
+from sqlalchemy.orm import declarative_base
+from sqlalchemy.orm import declared_attr
from sqlalchemy.orm import defer
from sqlalchemy.orm import deferred
from sqlalchemy.orm import eagerload
User.name.like("%j%")
)
eq_(list(q2), [(True,), (False,), (False,), (False,)])
+
+
+class DeclarativeBind(fixtures.TestBase):
+ def test_declarative_base(self):
+ with testing.expect_deprecated_20(
+ 'The "bind" argument to declarative_base is'
+ "deprecated and will be removed in SQLAlchemy 2.0.",
+ ):
+ Base = declarative_base(bind=testing.db)
+
+ is_true(Base.metadata.bind is testing.db)
+
+ def test_as_declarative(self):
+ with testing.expect_deprecated_20(
+ 'The "bind" argument to declarative_base is'
+ "deprecated and will be removed in SQLAlchemy 2.0.",
+ ):
+
+ @as_declarative(bind=testing.db)
+ class Base(object):
+ @declared_attr
+ def __tablename__(cls):
+ return cls.__name__.lower()
+
+ id = Column(Integer, primary_key=True)
+
+ is_true(Base.metadata.bind is testing.db)