~ubuntu-branches/debian/jessie/sqlalchemy/jessie

« back to all changes in this revision

Viewing changes to lib/sqlalchemy/ext/declarative/__init__.py

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski, Jakub Wilk, Piotr Ożarowski
  • Date: 2013-07-06 20:53:52 UTC
  • mfrom: (1.4.23) (16.1.17 experimental)
  • Revision ID: package-import@ubuntu.com-20130706205352-ryppl1eto3illd79
Tags: 0.8.2-1
[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

[ Piotr Ożarowski ]
* New upstream release
* Upload to unstable
* Build depend on python3-all instead of -dev, extensions are not built for
  Python 3.X 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# ext/declarative/__init__.py
 
2
# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file>
 
3
#
 
4
# This module is part of SQLAlchemy and is released under
 
5
# the MIT License: http://www.opensource.org/licenses/mit-license.php
 
6
 
 
7
"""
 
8
Synopsis
 
9
========
 
10
 
 
11
SQLAlchemy object-relational configuration involves the
 
12
combination of :class:`.Table`, :func:`.mapper`, and class
 
13
objects to define a mapped class.
 
14
:mod:`~sqlalchemy.ext.declarative` allows all three to be
 
15
expressed at once within the class declaration. As much as
 
16
possible, regular SQLAlchemy schema and ORM constructs are
 
17
used directly, so that configuration between "classical" ORM
 
18
usage and declarative remain highly similar.
 
19
 
 
20
As a simple example::
 
21
 
 
22
    from sqlalchemy.ext.declarative import declarative_base
 
23
 
 
24
    Base = declarative_base()
 
25
 
 
26
    class SomeClass(Base):
 
27
        __tablename__ = 'some_table'
 
28
        id = Column(Integer, primary_key=True)
 
29
        name =  Column(String(50))
 
30
 
 
31
Above, the :func:`declarative_base` callable returns a new base class from
 
32
which all mapped classes should inherit. When the class definition is
 
33
completed, a new :class:`.Table` and :func:`.mapper` will have been generated.
 
34
 
 
35
The resulting table and mapper are accessible via
 
36
``__table__`` and ``__mapper__`` attributes on the
 
37
``SomeClass`` class::
 
38
 
 
39
    # access the mapped Table
 
40
    SomeClass.__table__
 
41
 
 
42
    # access the Mapper
 
43
    SomeClass.__mapper__
 
44
 
 
45
Defining Attributes
 
46
===================
 
47
 
 
48
In the previous example, the :class:`.Column` objects are
 
49
automatically named with the name of the attribute to which they are
 
50
assigned.
 
51
 
 
52
To name columns explicitly with a name distinct from their mapped attribute,
 
53
just give the column a name.  Below, column "some_table_id" is mapped to the
 
54
"id" attribute of `SomeClass`, but in SQL will be represented as
 
55
"some_table_id"::
 
56
 
 
57
    class SomeClass(Base):
 
58
        __tablename__ = 'some_table'
 
59
        id = Column("some_table_id", Integer, primary_key=True)
 
60
 
 
61
Attributes may be added to the class after its construction, and they will be
 
62
added to the underlying :class:`.Table` and
 
63
:func:`.mapper` definitions as appropriate::
 
64
 
 
65
    SomeClass.data = Column('data', Unicode)
 
66
    SomeClass.related = relationship(RelatedInfo)
 
67
 
 
68
Classes which are constructed using declarative can interact freely
 
69
with classes that are mapped explicitly with :func:`.mapper`.
 
70
 
 
71
It is recommended, though not required, that all tables
 
72
share the same underlying :class:`~sqlalchemy.schema.MetaData` object,
 
73
so that string-configured :class:`~sqlalchemy.schema.ForeignKey`
 
74
references can be resolved without issue.
 
75
 
 
76
Accessing the MetaData
 
77
=======================
 
78
 
 
79
The :func:`declarative_base` base class contains a
 
80
:class:`.MetaData` object where newly defined
 
81
:class:`.Table` objects are collected. This object is
 
82
intended to be accessed directly for
 
83
:class:`.MetaData`-specific operations. Such as, to issue
 
84
CREATE statements for all tables::
 
85
 
 
86
    engine = create_engine('sqlite://')
 
87
    Base.metadata.create_all(engine)
 
88
 
 
89
:func:`declarative_base` can also receive a pre-existing
 
90
:class:`.MetaData` object, which allows a
 
91
declarative setup to be associated with an already
 
92
existing traditional collection of :class:`~sqlalchemy.schema.Table`
 
93
objects::
 
94
 
 
95
    mymetadata = MetaData()
 
96
    Base = declarative_base(metadata=mymetadata)
 
97
 
 
98
Configuring Relationships
 
99
=========================
 
100
 
 
101
Relationships to other classes are done in the usual way, with the added
 
102
feature that the class specified to :func:`~sqlalchemy.orm.relationship`
 
103
may be a string name.  The "class registry" associated with ``Base``
 
104
is used at mapper compilation time to resolve the name into the actual
 
105
class object, which is expected to have been defined once the mapper
 
106
configuration is used::
 
107
 
 
108
    class User(Base):
 
109
        __tablename__ = 'users'
 
110
 
 
111
        id = Column(Integer, primary_key=True)
 
112
        name = Column(String(50))
 
113
        addresses = relationship("Address", backref="user")
 
114
 
 
115
    class Address(Base):
 
116
        __tablename__ = 'addresses'
 
117
 
 
118
        id = Column(Integer, primary_key=True)
 
119
        email = Column(String(50))
 
120
        user_id = Column(Integer, ForeignKey('users.id'))
 
121
 
 
122
Column constructs, since they are just that, are immediately usable,
 
123
as below where we define a primary join condition on the ``Address``
 
124
class using them::
 
125
 
 
126
    class Address(Base):
 
127
        __tablename__ = 'addresses'
 
128
 
 
129
        id = Column(Integer, primary_key=True)
 
130
        email = Column(String(50))
 
131
        user_id = Column(Integer, ForeignKey('users.id'))
 
132
        user = relationship(User, primaryjoin=user_id == User.id)
 
133
 
 
134
In addition to the main argument for :func:`~sqlalchemy.orm.relationship`,
 
135
other arguments which depend upon the columns present on an as-yet
 
136
undefined class may also be specified as strings.  These strings are
 
137
evaluated as Python expressions.  The full namespace available within
 
138
this evaluation includes all classes mapped for this declarative base,
 
139
as well as the contents of the ``sqlalchemy`` package, including
 
140
expression functions like :func:`~sqlalchemy.sql.expression.desc` and
 
141
:attr:`~sqlalchemy.sql.expression.func`::
 
142
 
 
143
    class User(Base):
 
144
        # ....
 
145
        addresses = relationship("Address",
 
146
                             order_by="desc(Address.email)",
 
147
                             primaryjoin="Address.user_id==User.id")
 
148
 
 
149
For the case where more than one module contains a class of the same name,
 
150
string class names can also be specified as module-qualified paths
 
151
within any of these string expressions::
 
152
 
 
153
    class User(Base):
 
154
        # ....
 
155
        addresses = relationship("myapp.model.address.Address",
 
156
                             order_by="desc(myapp.model.address.Address.email)",
 
157
                             primaryjoin="myapp.model.address.Address.user_id=="
 
158
                                            "myapp.model.user.User.id")
 
159
 
 
160
The qualified path can be any partial path that removes ambiguity between
 
161
the names.  For example, to disambiguate between
 
162
``myapp.model.address.Address`` and ``myapp.model.lookup.Address``,
 
163
we can specify ``address.Address`` or ``lookup.Address``::
 
164
 
 
165
    class User(Base):
 
166
        # ....
 
167
        addresses = relationship("address.Address",
 
168
                             order_by="desc(address.Address.email)",
 
169
                             primaryjoin="address.Address.user_id=="
 
170
                                            "User.id")
 
171
 
 
172
.. versionadded:: 0.8
 
173
   module-qualified paths can be used when specifying string arguments
 
174
   with Declarative, in order to specify specific modules.
 
175
 
 
176
Two alternatives also exist to using string-based attributes.  A lambda
 
177
can also be used, which will be evaluated after all mappers have been
 
178
configured::
 
179
 
 
180
    class User(Base):
 
181
        # ...
 
182
        addresses = relationship(lambda: Address,
 
183
                             order_by=lambda: desc(Address.email),
 
184
                             primaryjoin=lambda: Address.user_id==User.id)
 
185
 
 
186
Or, the relationship can be added to the class explicitly after the classes
 
187
are available::
 
188
 
 
189
    User.addresses = relationship(Address,
 
190
                              primaryjoin=Address.user_id==User.id)
 
191
 
 
192
 
 
193
 
 
194
 
 
195
Configuring Many-to-Many Relationships
 
196
======================================
 
197
 
 
198
Many-to-many relationships are also declared in the same way
 
199
with declarative as with traditional mappings. The
 
200
``secondary`` argument to
 
201
:func:`.relationship` is as usual passed a
 
202
:class:`.Table` object, which is typically declared in the
 
203
traditional way.  The :class:`.Table` usually shares
 
204
the :class:`.MetaData` object used by the declarative base::
 
205
 
 
206
    keywords = Table(
 
207
        'keywords', Base.metadata,
 
208
        Column('author_id', Integer, ForeignKey('authors.id')),
 
209
        Column('keyword_id', Integer, ForeignKey('keywords.id'))
 
210
        )
 
211
 
 
212
    class Author(Base):
 
213
        __tablename__ = 'authors'
 
214
        id = Column(Integer, primary_key=True)
 
215
        keywords = relationship("Keyword", secondary=keywords)
 
216
 
 
217
Like other :func:`~sqlalchemy.orm.relationship` arguments, a string is accepted
 
218
as well, passing the string name of the table as defined in the
 
219
``Base.metadata.tables`` collection::
 
220
 
 
221
    class Author(Base):
 
222
        __tablename__ = 'authors'
 
223
        id = Column(Integer, primary_key=True)
 
224
        keywords = relationship("Keyword", secondary="keywords")
 
225
 
 
226
As with traditional mapping, its generally not a good idea to use
 
227
a :class:`.Table` as the "secondary" argument which is also mapped to
 
228
a class, unless the :func:`.relationship` is declared with ``viewonly=True``.
 
229
Otherwise, the unit-of-work system may attempt duplicate INSERT and
 
230
DELETE statements against the underlying table.
 
231
 
 
232
.. _declarative_sql_expressions:
 
233
 
 
234
Defining SQL Expressions
 
235
========================
 
236
 
 
237
See :ref:`mapper_sql_expressions` for examples on declaratively
 
238
mapping attributes to SQL expressions.
 
239
 
 
240
.. _declarative_table_args:
 
241
 
 
242
Table Configuration
 
243
===================
 
244
 
 
245
Table arguments other than the name, metadata, and mapped Column
 
246
arguments are specified using the ``__table_args__`` class attribute.
 
247
This attribute accommodates both positional as well as keyword
 
248
arguments that are normally sent to the
 
249
:class:`~sqlalchemy.schema.Table` constructor.
 
250
The attribute can be specified in one of two forms. One is as a
 
251
dictionary::
 
252
 
 
253
    class MyClass(Base):
 
254
        __tablename__ = 'sometable'
 
255
        __table_args__ = {'mysql_engine':'InnoDB'}
 
256
 
 
257
The other, a tuple, where each argument is positional
 
258
(usually constraints)::
 
259
 
 
260
    class MyClass(Base):
 
261
        __tablename__ = 'sometable'
 
262
        __table_args__ = (
 
263
                ForeignKeyConstraint(['id'], ['remote_table.id']),
 
264
                UniqueConstraint('foo'),
 
265
                )
 
266
 
 
267
Keyword arguments can be specified with the above form by
 
268
specifying the last argument as a dictionary::
 
269
 
 
270
    class MyClass(Base):
 
271
        __tablename__ = 'sometable'
 
272
        __table_args__ = (
 
273
                ForeignKeyConstraint(['id'], ['remote_table.id']),
 
274
                UniqueConstraint('foo'),
 
275
                {'autoload':True}
 
276
                )
 
277
 
 
278
Using a Hybrid Approach with __table__
 
279
=======================================
 
280
 
 
281
As an alternative to ``__tablename__``, a direct
 
282
:class:`~sqlalchemy.schema.Table` construct may be used.  The
 
283
:class:`~sqlalchemy.schema.Column` objects, which in this case require
 
284
their names, will be added to the mapping just like a regular mapping
 
285
to a table::
 
286
 
 
287
    class MyClass(Base):
 
288
        __table__ = Table('my_table', Base.metadata,
 
289
            Column('id', Integer, primary_key=True),
 
290
            Column('name', String(50))
 
291
        )
 
292
 
 
293
``__table__`` provides a more focused point of control for establishing
 
294
table metadata, while still getting most of the benefits of using declarative.
 
295
An application that uses reflection might want to load table metadata elsewhere
 
296
and pass it to declarative classes::
 
297
 
 
298
    from sqlalchemy.ext.declarative import declarative_base
 
299
 
 
300
    Base = declarative_base()
 
301
    Base.metadata.reflect(some_engine)
 
302
 
 
303
    class User(Base):
 
304
        __table__ = metadata.tables['user']
 
305
 
 
306
    class Address(Base):
 
307
        __table__ = metadata.tables['address']
 
308
 
 
309
Some configuration schemes may find it more appropriate to use ``__table__``,
 
310
such as those which already take advantage of the data-driven nature of
 
311
:class:`.Table` to customize and/or automate schema definition.
 
312
 
 
313
Note that when the ``__table__`` approach is used, the object is immediately
 
314
usable as a plain :class:`.Table` within the class declaration body itself,
 
315
as a Python class is only another syntactical block.  Below this is illustrated
 
316
by using the ``id`` column in the ``primaryjoin`` condition of a
 
317
:func:`.relationship`::
 
318
 
 
319
    class MyClass(Base):
 
320
        __table__ = Table('my_table', Base.metadata,
 
321
            Column('id', Integer, primary_key=True),
 
322
            Column('name', String(50))
 
323
        )
 
324
 
 
325
        widgets = relationship(Widget,
 
326
                    primaryjoin=Widget.myclass_id==__table__.c.id)
 
327
 
 
328
Similarly, mapped attributes which refer to ``__table__`` can be placed inline,
 
329
as below where we assign the ``name`` column to the attribute ``_name``,
 
330
generating a synonym for ``name``::
 
331
 
 
332
    from sqlalchemy.ext.declarative import synonym_for
 
333
 
 
334
    class MyClass(Base):
 
335
        __table__ = Table('my_table', Base.metadata,
 
336
            Column('id', Integer, primary_key=True),
 
337
            Column('name', String(50))
 
338
        )
 
339
 
 
340
        _name = __table__.c.name
 
341
 
 
342
        @synonym_for("_name")
 
343
        def name(self):
 
344
            return "Name: %s" % _name
 
345
 
 
346
Using Reflection with Declarative
 
347
=================================
 
348
 
 
349
It's easy to set up a :class:`.Table` that uses ``autoload=True``
 
350
in conjunction with a mapped class::
 
351
 
 
352
    class MyClass(Base):
 
353
        __table__ = Table('mytable', Base.metadata,
 
354
                        autoload=True, autoload_with=some_engine)
 
355
 
 
356
However, one improvement that can be made here is to not
 
357
require the :class:`.Engine` to be available when classes are
 
358
being first declared.   To achieve this, use the
 
359
:class:`.DeferredReflection` mixin, which sets up mappings
 
360
only after a special ``prepare(engine)`` step is called::
 
361
 
 
362
    from sqlalchemy.ext.declarative import declarative_base, DeferredReflection
 
363
 
 
364
    Base = declarative_base(cls=DeferredReflection)
 
365
 
 
366
    class Foo(Base):
 
367
        __tablename__ = 'foo'
 
368
        bars = relationship("Bar")
 
369
 
 
370
    class Bar(Base):
 
371
        __tablename__ = 'bar'
 
372
 
 
373
        # illustrate overriding of "bar.foo_id" to have
 
374
        # a foreign key constraint otherwise not
 
375
        # reflected, such as when using MySQL
 
376
        foo_id = Column(Integer, ForeignKey('foo.id'))
 
377
 
 
378
    Base.prepare(e)
 
379
 
 
380
.. versionadded:: 0.8
 
381
   Added :class:`.DeferredReflection`.
 
382
 
 
383
Mapper Configuration
 
384
====================
 
385
 
 
386
Declarative makes use of the :func:`~.orm.mapper` function internally
 
387
when it creates the mapping to the declared table.   The options
 
388
for :func:`~.orm.mapper` are passed directly through via the
 
389
``__mapper_args__`` class attribute.  As always, arguments which reference
 
390
locally mapped columns can reference them directly from within the
 
391
class declaration::
 
392
 
 
393
    from datetime import datetime
 
394
 
 
395
    class Widget(Base):
 
396
        __tablename__ = 'widgets'
 
397
 
 
398
        id = Column(Integer, primary_key=True)
 
399
        timestamp = Column(DateTime, nullable=False)
 
400
 
 
401
        __mapper_args__ = {
 
402
                        'version_id_col': timestamp,
 
403
                        'version_id_generator': lambda v:datetime.now()
 
404
                    }
 
405
 
 
406
.. _declarative_inheritance:
 
407
 
 
408
Inheritance Configuration
 
409
=========================
 
410
 
 
411
Declarative supports all three forms of inheritance as intuitively
 
412
as possible.  The ``inherits`` mapper keyword argument is not needed
 
413
as declarative will determine this from the class itself.   The various
 
414
"polymorphic" keyword arguments are specified using ``__mapper_args__``.
 
415
 
 
416
Joined Table Inheritance
 
417
~~~~~~~~~~~~~~~~~~~~~~~~
 
418
 
 
419
Joined table inheritance is defined as a subclass that defines its own
 
420
table::
 
421
 
 
422
    class Person(Base):
 
423
        __tablename__ = 'people'
 
424
        id = Column(Integer, primary_key=True)
 
425
        discriminator = Column('type', String(50))
 
426
        __mapper_args__ = {'polymorphic_on': discriminator}
 
427
 
 
428
    class Engineer(Person):
 
429
        __tablename__ = 'engineers'
 
430
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
431
        id = Column(Integer, ForeignKey('people.id'), primary_key=True)
 
432
        primary_language = Column(String(50))
 
433
 
 
434
Note that above, the ``Engineer.id`` attribute, since it shares the
 
435
same attribute name as the ``Person.id`` attribute, will in fact
 
436
represent the ``people.id`` and ``engineers.id`` columns together,
 
437
with the "Engineer.id" column taking precedence if queried directly.
 
438
To provide the ``Engineer`` class with an attribute that represents
 
439
only the ``engineers.id`` column, give it a different attribute name::
 
440
 
 
441
    class Engineer(Person):
 
442
        __tablename__ = 'engineers'
 
443
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
444
        engineer_id = Column('id', Integer, ForeignKey('people.id'),
 
445
                                                    primary_key=True)
 
446
        primary_language = Column(String(50))
 
447
 
 
448
 
 
449
.. versionchanged:: 0.7 joined table inheritance favors the subclass
 
450
   column over that of the superclass, such as querying above
 
451
   for ``Engineer.id``.  Prior to 0.7 this was the reverse.
 
452
 
 
453
.. _declarative_single_table:
 
454
 
 
455
Single Table Inheritance
 
456
~~~~~~~~~~~~~~~~~~~~~~~~
 
457
 
 
458
Single table inheritance is defined as a subclass that does not have
 
459
its own table; you just leave out the ``__table__`` and ``__tablename__``
 
460
attributes::
 
461
 
 
462
    class Person(Base):
 
463
        __tablename__ = 'people'
 
464
        id = Column(Integer, primary_key=True)
 
465
        discriminator = Column('type', String(50))
 
466
        __mapper_args__ = {'polymorphic_on': discriminator}
 
467
 
 
468
    class Engineer(Person):
 
469
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
470
        primary_language = Column(String(50))
 
471
 
 
472
When the above mappers are configured, the ``Person`` class is mapped
 
473
to the ``people`` table *before* the ``primary_language`` column is
 
474
defined, and this column will not be included in its own mapping.
 
475
When ``Engineer`` then defines the ``primary_language`` column, the
 
476
column is added to the ``people`` table so that it is included in the
 
477
mapping for ``Engineer`` and is also part of the table's full set of
 
478
columns.  Columns which are not mapped to ``Person`` are also excluded
 
479
from any other single or joined inheriting classes using the
 
480
``exclude_properties`` mapper argument.  Below, ``Manager`` will have
 
481
all the attributes of ``Person`` and ``Manager`` but *not* the
 
482
``primary_language`` attribute of ``Engineer``::
 
483
 
 
484
    class Manager(Person):
 
485
        __mapper_args__ = {'polymorphic_identity': 'manager'}
 
486
        golf_swing = Column(String(50))
 
487
 
 
488
The attribute exclusion logic is provided by the
 
489
``exclude_properties`` mapper argument, and declarative's default
 
490
behavior can be disabled by passing an explicit ``exclude_properties``
 
491
collection (empty or otherwise) to the ``__mapper_args__``.
 
492
 
 
493
Resolving Column Conflicts
 
494
^^^^^^^^^^^^^^^^^^^^^^^^^^
 
495
 
 
496
Note above that the ``primary_language`` and ``golf_swing`` columns
 
497
are "moved up" to be applied to ``Person.__table__``, as a result of their
 
498
declaration on a subclass that has no table of its own.   A tricky case
 
499
comes up when two subclasses want to specify *the same* column, as below::
 
500
 
 
501
    class Person(Base):
 
502
        __tablename__ = 'people'
 
503
        id = Column(Integer, primary_key=True)
 
504
        discriminator = Column('type', String(50))
 
505
        __mapper_args__ = {'polymorphic_on': discriminator}
 
506
 
 
507
    class Engineer(Person):
 
508
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
509
        start_date = Column(DateTime)
 
510
 
 
511
    class Manager(Person):
 
512
        __mapper_args__ = {'polymorphic_identity': 'manager'}
 
513
        start_date = Column(DateTime)
 
514
 
 
515
Above, the ``start_date`` column declared on both ``Engineer`` and ``Manager``
 
516
will result in an error::
 
517
 
 
518
    sqlalchemy.exc.ArgumentError: Column 'start_date' on class
 
519
    <class '__main__.Manager'> conflicts with existing
 
520
    column 'people.start_date'
 
521
 
 
522
In a situation like this, Declarative can't be sure
 
523
of the intent, especially if the ``start_date`` columns had, for example,
 
524
different types.   A situation like this can be resolved by using
 
525
:class:`.declared_attr` to define the :class:`.Column` conditionally, taking
 
526
care to return the **existing column** via the parent ``__table__`` if it
 
527
already exists::
 
528
 
 
529
    from sqlalchemy.ext.declarative import declared_attr
 
530
 
 
531
    class Person(Base):
 
532
        __tablename__ = 'people'
 
533
        id = Column(Integer, primary_key=True)
 
534
        discriminator = Column('type', String(50))
 
535
        __mapper_args__ = {'polymorphic_on': discriminator}
 
536
 
 
537
    class Engineer(Person):
 
538
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
539
 
 
540
        @declared_attr
 
541
        def start_date(cls):
 
542
            "Start date column, if not present already."
 
543
            return Person.__table__.c.get('start_date', Column(DateTime))
 
544
 
 
545
    class Manager(Person):
 
546
        __mapper_args__ = {'polymorphic_identity': 'manager'}
 
547
 
 
548
        @declared_attr
 
549
        def start_date(cls):
 
550
            "Start date column, if not present already."
 
551
            return Person.__table__.c.get('start_date', Column(DateTime))
 
552
 
 
553
Above, when ``Manager`` is mapped, the ``start_date`` column is
 
554
already present on the ``Person`` class.  Declarative lets us return
 
555
that :class:`.Column` as a result in this case, where it knows to skip
 
556
re-assigning the same column. If the mapping is mis-configured such
 
557
that the ``start_date`` column is accidentally re-assigned to a
 
558
different table (such as, if we changed ``Manager`` to be joined
 
559
inheritance without fixing ``start_date``), an error is raised which
 
560
indicates an existing :class:`.Column` is trying to be re-assigned to
 
561
a different owning :class:`.Table`.
 
562
 
 
563
.. versionadded:: 0.8 :class:`.declared_attr` can be used on a non-mixin
 
564
   class, and the returned :class:`.Column` or other mapped attribute
 
565
   will be applied to the mapping as any other attribute.  Previously,
 
566
   the resulting attribute would be ignored, and also result in a warning
 
567
   being emitted when a subclass was created.
 
568
 
 
569
.. versionadded:: 0.8 :class:`.declared_attr`, when used either with a
 
570
   mixin or non-mixin declarative class, can return an existing
 
571
   :class:`.Column` already assigned to the parent :class:`.Table`,
 
572
   to indicate that the re-assignment of the :class:`.Column` should be
 
573
   skipped, however should still be mapped on the target class,
 
574
   in order to resolve duplicate column conflicts.
 
575
 
 
576
The same concept can be used with mixin classes (see
 
577
:ref:`declarative_mixins`)::
 
578
 
 
579
    class Person(Base):
 
580
        __tablename__ = 'people'
 
581
        id = Column(Integer, primary_key=True)
 
582
        discriminator = Column('type', String(50))
 
583
        __mapper_args__ = {'polymorphic_on': discriminator}
 
584
 
 
585
    class HasStartDate(object):
 
586
        @declared_attr
 
587
        def start_date(cls):
 
588
            return cls.__table__.c.get('start_date', Column(DateTime))
 
589
 
 
590
    class Engineer(HasStartDate, Person):
 
591
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
592
 
 
593
    class Manager(HasStartDate, Person):
 
594
        __mapper_args__ = {'polymorphic_identity': 'manager'}
 
595
 
 
596
The above mixin checks the local ``__table__`` attribute for the column.
 
597
Because we're using single table inheritance, we're sure that in this case,
 
598
``cls.__table__`` refers to ``People.__table__``.  If we were mixing joined-
 
599
and single-table inheritance, we might want our mixin to check more carefully
 
600
if ``cls.__table__`` is really the :class:`.Table` we're looking for.
 
601
 
 
602
Concrete Table Inheritance
 
603
~~~~~~~~~~~~~~~~~~~~~~~~~~
 
604
 
 
605
Concrete is defined as a subclass which has its own table and sets the
 
606
``concrete`` keyword argument to ``True``::
 
607
 
 
608
    class Person(Base):
 
609
        __tablename__ = 'people'
 
610
        id = Column(Integer, primary_key=True)
 
611
        name = Column(String(50))
 
612
 
 
613
    class Engineer(Person):
 
614
        __tablename__ = 'engineers'
 
615
        __mapper_args__ = {'concrete':True}
 
616
        id = Column(Integer, primary_key=True)
 
617
        primary_language = Column(String(50))
 
618
        name = Column(String(50))
 
619
 
 
620
Usage of an abstract base class is a little less straightforward as it
 
621
requires usage of :func:`~sqlalchemy.orm.util.polymorphic_union`,
 
622
which needs to be created with the :class:`.Table` objects
 
623
before the class is built::
 
624
 
 
625
    engineers = Table('engineers', Base.metadata,
 
626
                    Column('id', Integer, primary_key=True),
 
627
                    Column('name', String(50)),
 
628
                    Column('primary_language', String(50))
 
629
                )
 
630
    managers = Table('managers', Base.metadata,
 
631
                    Column('id', Integer, primary_key=True),
 
632
                    Column('name', String(50)),
 
633
                    Column('golf_swing', String(50))
 
634
                )
 
635
 
 
636
    punion = polymorphic_union({
 
637
        'engineer':engineers,
 
638
        'manager':managers
 
639
    }, 'type', 'punion')
 
640
 
 
641
    class Person(Base):
 
642
        __table__ = punion
 
643
        __mapper_args__ = {'polymorphic_on':punion.c.type}
 
644
 
 
645
    class Engineer(Person):
 
646
        __table__ = engineers
 
647
        __mapper_args__ = {'polymorphic_identity':'engineer', 'concrete':True}
 
648
 
 
649
    class Manager(Person):
 
650
        __table__ = managers
 
651
        __mapper_args__ = {'polymorphic_identity':'manager', 'concrete':True}
 
652
 
 
653
.. _declarative_concrete_helpers:
 
654
 
 
655
Using the Concrete Helpers
 
656
^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
657
 
 
658
Helper classes provides a simpler pattern for concrete inheritance.
 
659
With these objects, the ``__declare_last__`` helper is used to configure the
 
660
"polymorphic" loader for the mapper after all subclasses have been declared.
 
661
 
 
662
.. versionadded:: 0.7.3
 
663
 
 
664
An abstract base can be declared using the
 
665
:class:`.AbstractConcreteBase` class::
 
666
 
 
667
    from sqlalchemy.ext.declarative import AbstractConcreteBase
 
668
 
 
669
    class Employee(AbstractConcreteBase, Base):
 
670
        pass
 
671
 
 
672
To have a concrete ``employee`` table, use :class:`.ConcreteBase` instead::
 
673
 
 
674
    from sqlalchemy.ext.declarative import ConcreteBase
 
675
 
 
676
    class Employee(ConcreteBase, Base):
 
677
        __tablename__ = 'employee'
 
678
        employee_id = Column(Integer, primary_key=True)
 
679
        name = Column(String(50))
 
680
        __mapper_args__ = {
 
681
                        'polymorphic_identity':'employee',
 
682
                        'concrete':True}
 
683
 
 
684
 
 
685
Either ``Employee`` base can be used in the normal fashion::
 
686
 
 
687
    class Manager(Employee):
 
688
        __tablename__ = 'manager'
 
689
        employee_id = Column(Integer, primary_key=True)
 
690
        name = Column(String(50))
 
691
        manager_data = Column(String(40))
 
692
        __mapper_args__ = {
 
693
                        'polymorphic_identity':'manager',
 
694
                        'concrete':True}
 
695
 
 
696
    class Engineer(Employee):
 
697
        __tablename__ = 'engineer'
 
698
        employee_id = Column(Integer, primary_key=True)
 
699
        name = Column(String(50))
 
700
        engineer_info = Column(String(40))
 
701
        __mapper_args__ = {'polymorphic_identity':'engineer',
 
702
                        'concrete':True}
 
703
 
 
704
 
 
705
.. _declarative_mixins:
 
706
 
 
707
Mixin and Custom Base Classes
 
708
==============================
 
709
 
 
710
A common need when using :mod:`~sqlalchemy.ext.declarative` is to
 
711
share some functionality, such as a set of common columns, some common
 
712
table options, or other mapped properties, across many
 
713
classes.  The standard Python idioms for this is to have the classes
 
714
inherit from a base which includes these common features.
 
715
 
 
716
When using :mod:`~sqlalchemy.ext.declarative`, this idiom is allowed
 
717
via the usage of a custom declarative base class, as well as a "mixin" class
 
718
which is inherited from in addition to the primary base.  Declarative
 
719
includes several helper features to make this work in terms of how
 
720
mappings are declared.   An example of some commonly mixed-in
 
721
idioms is below::
 
722
 
 
723
    from sqlalchemy.ext.declarative import declared_attr
 
724
 
 
725
    class MyMixin(object):
 
726
 
 
727
        @declared_attr
 
728
        def __tablename__(cls):
 
729
            return cls.__name__.lower()
 
730
 
 
731
        __table_args__ = {'mysql_engine': 'InnoDB'}
 
732
        __mapper_args__= {'always_refresh': True}
 
733
 
 
734
        id =  Column(Integer, primary_key=True)
 
735
 
 
736
    class MyModel(MyMixin, Base):
 
737
        name = Column(String(1000))
 
738
 
 
739
Where above, the class ``MyModel`` will contain an "id" column
 
740
as the primary key, a ``__tablename__`` attribute that derives
 
741
from the name of the class itself, as well as ``__table_args__``
 
742
and ``__mapper_args__`` defined by the ``MyMixin`` mixin class.
 
743
 
 
744
There's no fixed convention over whether ``MyMixin`` precedes
 
745
``Base`` or not.  Normal Python method resolution rules apply, and
 
746
the above example would work just as well with::
 
747
 
 
748
    class MyModel(Base, MyMixin):
 
749
        name = Column(String(1000))
 
750
 
 
751
This works because ``Base`` here doesn't define any of the
 
752
variables that ``MyMixin`` defines, i.e. ``__tablename__``,
 
753
``__table_args__``, ``id``, etc.   If the ``Base`` did define
 
754
an attribute of the same name, the class placed first in the
 
755
inherits list would determine which attribute is used on the
 
756
newly defined class.
 
757
 
 
758
Augmenting the Base
 
759
~~~~~~~~~~~~~~~~~~~
 
760
 
 
761
In addition to using a pure mixin, most of the techniques in this
 
762
section can also be applied to the base class itself, for patterns that
 
763
should apply to all classes derived from a particular base.  This is achieved
 
764
using the ``cls`` argument of the :func:`.declarative_base` function::
 
765
 
 
766
    from sqlalchemy.ext.declarative import declared_attr
 
767
 
 
768
    class Base(object):
 
769
        @declared_attr
 
770
        def __tablename__(cls):
 
771
            return cls.__name__.lower()
 
772
 
 
773
        __table_args__ = {'mysql_engine': 'InnoDB'}
 
774
 
 
775
        id =  Column(Integer, primary_key=True)
 
776
 
 
777
    from sqlalchemy.ext.declarative import declarative_base
 
778
 
 
779
    Base = declarative_base(cls=Base)
 
780
 
 
781
    class MyModel(Base):
 
782
        name = Column(String(1000))
 
783
 
 
784
Where above, ``MyModel`` and all other classes that derive from ``Base`` will
 
785
have a table name derived from the class name, an ``id`` primary key column,
 
786
as well as the "InnoDB" engine for MySQL.
 
787
 
 
788
Mixing in Columns
 
789
~~~~~~~~~~~~~~~~~
 
790
 
 
791
The most basic way to specify a column on a mixin is by simple
 
792
declaration::
 
793
 
 
794
    class TimestampMixin(object):
 
795
        created_at = Column(DateTime, default=func.now())
 
796
 
 
797
    class MyModel(TimestampMixin, Base):
 
798
        __tablename__ = 'test'
 
799
 
 
800
        id =  Column(Integer, primary_key=True)
 
801
        name = Column(String(1000))
 
802
 
 
803
Where above, all declarative classes that include ``TimestampMixin``
 
804
will also have a column ``created_at`` that applies a timestamp to
 
805
all row insertions.
 
806
 
 
807
Those familiar with the SQLAlchemy expression language know that
 
808
the object identity of clause elements defines their role in a schema.
 
809
Two ``Table`` objects ``a`` and ``b`` may both have a column called
 
810
``id``, but the way these are differentiated is that ``a.c.id``
 
811
and ``b.c.id`` are two distinct Python objects, referencing their
 
812
parent tables ``a`` and ``b`` respectively.
 
813
 
 
814
In the case of the mixin column, it seems that only one
 
815
:class:`.Column` object is explicitly created, yet the ultimate
 
816
``created_at`` column above must exist as a distinct Python object
 
817
for each separate destination class.  To accomplish this, the declarative
 
818
extension creates a **copy** of each :class:`.Column` object encountered on
 
819
a class that is detected as a mixin.
 
820
 
 
821
This copy mechanism is limited to simple columns that have no foreign
 
822
keys, as a :class:`.ForeignKey` itself contains references to columns
 
823
which can't be properly recreated at this level.  For columns that
 
824
have foreign keys, as well as for the variety of mapper-level constructs
 
825
that require destination-explicit context, the
 
826
:class:`~.declared_attr` decorator is provided so that
 
827
patterns common to many classes can be defined as callables::
 
828
 
 
829
    from sqlalchemy.ext.declarative import declared_attr
 
830
 
 
831
    class ReferenceAddressMixin(object):
 
832
        @declared_attr
 
833
        def address_id(cls):
 
834
            return Column(Integer, ForeignKey('address.id'))
 
835
 
 
836
    class User(ReferenceAddressMixin, Base):
 
837
        __tablename__ = 'user'
 
838
        id = Column(Integer, primary_key=True)
 
839
 
 
840
Where above, the ``address_id`` class-level callable is executed at the
 
841
point at which the ``User`` class is constructed, and the declarative
 
842
extension can use the resulting :class:`.Column` object as returned by
 
843
the method without the need to copy it.
 
844
 
 
845
.. versionchanged:: > 0.6.5
 
846
    Rename 0.6.5 ``sqlalchemy.util.classproperty``
 
847
    into :class:`~.declared_attr`.
 
848
 
 
849
Columns generated by :class:`~.declared_attr` can also be
 
850
referenced by ``__mapper_args__`` to a limited degree, currently
 
851
by ``polymorphic_on`` and ``version_id_col``, by specifying the
 
852
classdecorator itself into the dictionary - the declarative extension
 
853
will resolve them at class construction time::
 
854
 
 
855
    class MyMixin:
 
856
        @declared_attr
 
857
        def type_(cls):
 
858
            return Column(String(50))
 
859
 
 
860
        __mapper_args__= {'polymorphic_on':type_}
 
861
 
 
862
    class MyModel(MyMixin, Base):
 
863
        __tablename__='test'
 
864
        id =  Column(Integer, primary_key=True)
 
865
 
 
866
 
 
867
 
 
868
Mixing in Relationships
 
869
~~~~~~~~~~~~~~~~~~~~~~~
 
870
 
 
871
Relationships created by :func:`~sqlalchemy.orm.relationship` are provided
 
872
with declarative mixin classes exclusively using the
 
873
:class:`.declared_attr` approach, eliminating any ambiguity
 
874
which could arise when copying a relationship and its possibly column-bound
 
875
contents. Below is an example which combines a foreign key column and a
 
876
relationship so that two classes ``Foo`` and ``Bar`` can both be configured to
 
877
reference a common target class via many-to-one::
 
878
 
 
879
    class RefTargetMixin(object):
 
880
        @declared_attr
 
881
        def target_id(cls):
 
882
            return Column('target_id', ForeignKey('target.id'))
 
883
 
 
884
        @declared_attr
 
885
        def target(cls):
 
886
            return relationship("Target")
 
887
 
 
888
    class Foo(RefTargetMixin, Base):
 
889
        __tablename__ = 'foo'
 
890
        id = Column(Integer, primary_key=True)
 
891
 
 
892
    class Bar(RefTargetMixin, Base):
 
893
        __tablename__ = 'bar'
 
894
        id = Column(Integer, primary_key=True)
 
895
 
 
896
    class Target(Base):
 
897
        __tablename__ = 'target'
 
898
        id = Column(Integer, primary_key=True)
 
899
 
 
900
:func:`~sqlalchemy.orm.relationship` definitions which require explicit
 
901
primaryjoin, order_by etc. expressions should use the string forms
 
902
for these arguments, so that they are evaluated as late as possible.
 
903
To reference the mixin class in these expressions, use the given ``cls``
 
904
to get its name::
 
905
 
 
906
    class RefTargetMixin(object):
 
907
        @declared_attr
 
908
        def target_id(cls):
 
909
            return Column('target_id', ForeignKey('target.id'))
 
910
 
 
911
        @declared_attr
 
912
        def target(cls):
 
913
            return relationship("Target",
 
914
                primaryjoin="Target.id==%s.target_id" % cls.__name__
 
915
            )
 
916
 
 
917
Mixing in deferred(), column_property(), and other MapperProperty classes
 
918
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
919
 
 
920
Like :func:`~sqlalchemy.orm.relationship`, all
 
921
:class:`~sqlalchemy.orm.interfaces.MapperProperty` subclasses such as
 
922
:func:`~sqlalchemy.orm.deferred`, :func:`~sqlalchemy.orm.column_property`,
 
923
etc. ultimately involve references to columns, and therefore, when
 
924
used with declarative mixins, have the :class:`.declared_attr`
 
925
requirement so that no reliance on copying is needed::
 
926
 
 
927
    class SomethingMixin(object):
 
928
 
 
929
        @declared_attr
 
930
        def dprop(cls):
 
931
            return deferred(Column(Integer))
 
932
 
 
933
    class Something(SomethingMixin, Base):
 
934
        __tablename__ = "something"
 
935
 
 
936
Mixing in Association Proxy and Other Attributes
 
937
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
938
 
 
939
Mixins can specify user-defined attributes as well as other extension
 
940
units such as :func:`.association_proxy`.   The usage of
 
941
:class:`.declared_attr` is required in those cases where the attribute must
 
942
be tailored specifically to the target subclass.   An example is when
 
943
constructing multiple :func:`.association_proxy` attributes which each
 
944
target a different type of child object.  Below is an
 
945
:func:`.association_proxy` / mixin example which provides a scalar list of
 
946
string values to an implementing class::
 
947
 
 
948
    from sqlalchemy import Column, Integer, ForeignKey, String
 
949
    from sqlalchemy.orm import relationship
 
950
    from sqlalchemy.ext.associationproxy import association_proxy
 
951
    from sqlalchemy.ext.declarative import declarative_base, declared_attr
 
952
 
 
953
    Base = declarative_base()
 
954
 
 
955
    class HasStringCollection(object):
 
956
        @declared_attr
 
957
        def _strings(cls):
 
958
            class StringAttribute(Base):
 
959
                __tablename__ = cls.string_table_name
 
960
                id = Column(Integer, primary_key=True)
 
961
                value = Column(String(50), nullable=False)
 
962
                parent_id = Column(Integer,
 
963
                                ForeignKey('%s.id' % cls.__tablename__),
 
964
                                nullable=False)
 
965
                def __init__(self, value):
 
966
                    self.value = value
 
967
 
 
968
            return relationship(StringAttribute)
 
969
 
 
970
        @declared_attr
 
971
        def strings(cls):
 
972
            return association_proxy('_strings', 'value')
 
973
 
 
974
    class TypeA(HasStringCollection, Base):
 
975
        __tablename__ = 'type_a'
 
976
        string_table_name = 'type_a_strings'
 
977
        id = Column(Integer(), primary_key=True)
 
978
 
 
979
    class TypeB(HasStringCollection, Base):
 
980
        __tablename__ = 'type_b'
 
981
        string_table_name = 'type_b_strings'
 
982
        id = Column(Integer(), primary_key=True)
 
983
 
 
984
Above, the ``HasStringCollection`` mixin produces a :func:`.relationship`
 
985
which refers to a newly generated class called ``StringAttribute``.  The
 
986
``StringAttribute`` class is generated with it's own :class:`.Table`
 
987
definition which is local to the parent class making usage of the
 
988
``HasStringCollection`` mixin.  It also produces an :func:`.association_proxy`
 
989
object which proxies references to the ``strings`` attribute onto the ``value``
 
990
attribute of each ``StringAttribute`` instance.
 
991
 
 
992
``TypeA`` or ``TypeB`` can be instantiated given the constructor
 
993
argument ``strings``, a list of strings::
 
994
 
 
995
    ta = TypeA(strings=['foo', 'bar'])
 
996
    tb = TypeA(strings=['bat', 'bar'])
 
997
 
 
998
This list will generate a collection
 
999
of ``StringAttribute`` objects, which are persisted into a table that's
 
1000
local to either the ``type_a_strings`` or ``type_b_strings`` table::
 
1001
 
 
1002
    >>> print ta._strings
 
1003
    [<__main__.StringAttribute object at 0x10151cd90>,
 
1004
        <__main__.StringAttribute object at 0x10151ce10>]
 
1005
 
 
1006
When constructing the :func:`.association_proxy`, the
 
1007
:class:`.declared_attr` decorator must be used so that a distinct
 
1008
:func:`.association_proxy` object is created for each of the ``TypeA``
 
1009
and ``TypeB`` classes.
 
1010
 
 
1011
.. versionadded:: 0.8 :class:`.declared_attr` is usable with non-mapped
 
1012
   attributes, including user-defined attributes as well as
 
1013
   :func:`.association_proxy`.
 
1014
 
 
1015
 
 
1016
Controlling table inheritance with mixins
 
1017
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
1018
 
 
1019
The ``__tablename__`` attribute in conjunction with the hierarchy of
 
1020
classes involved in a declarative mixin scenario controls what type of
 
1021
table inheritance, if any,
 
1022
is configured by the declarative extension.
 
1023
 
 
1024
If the ``__tablename__`` is computed by a mixin, you may need to
 
1025
control which classes get the computed attribute in order to get the
 
1026
type of table inheritance you require.
 
1027
 
 
1028
For example, if you had a mixin that computes ``__tablename__`` but
 
1029
where you wanted to use that mixin in a single table inheritance
 
1030
hierarchy, you can explicitly specify ``__tablename__`` as ``None`` to
 
1031
indicate that the class should not have a table mapped::
 
1032
 
 
1033
    from sqlalchemy.ext.declarative import declared_attr
 
1034
 
 
1035
    class Tablename:
 
1036
        @declared_attr
 
1037
        def __tablename__(cls):
 
1038
            return cls.__name__.lower()
 
1039
 
 
1040
    class Person(Tablename, Base):
 
1041
        id = Column(Integer, primary_key=True)
 
1042
        discriminator = Column('type', String(50))
 
1043
        __mapper_args__ = {'polymorphic_on': discriminator}
 
1044
 
 
1045
    class Engineer(Person):
 
1046
        __tablename__ = None
 
1047
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
1048
        primary_language = Column(String(50))
 
1049
 
 
1050
Alternatively, you can make the mixin intelligent enough to only
 
1051
return a ``__tablename__`` in the event that no table is already
 
1052
mapped in the inheritance hierarchy. To help with this, a
 
1053
:func:`~sqlalchemy.ext.declarative.has_inherited_table` helper
 
1054
function is provided that returns ``True`` if a parent class already
 
1055
has a mapped table.
 
1056
 
 
1057
As an example, here's a mixin that will only allow single table
 
1058
inheritance::
 
1059
 
 
1060
    from sqlalchemy.ext.declarative import declared_attr
 
1061
    from sqlalchemy.ext.declarative import has_inherited_table
 
1062
 
 
1063
    class Tablename(object):
 
1064
        @declared_attr
 
1065
        def __tablename__(cls):
 
1066
            if has_inherited_table(cls):
 
1067
                return None
 
1068
            return cls.__name__.lower()
 
1069
 
 
1070
    class Person(Tablename, Base):
 
1071
        id = Column(Integer, primary_key=True)
 
1072
        discriminator = Column('type', String(50))
 
1073
        __mapper_args__ = {'polymorphic_on': discriminator}
 
1074
 
 
1075
    class Engineer(Person):
 
1076
        primary_language = Column(String(50))
 
1077
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
1078
 
 
1079
If you want to use a similar pattern with a mix of single and joined
 
1080
table inheritance, you would need a slightly different mixin and use
 
1081
it on any joined table child classes in addition to their parent
 
1082
classes::
 
1083
 
 
1084
    from sqlalchemy.ext.declarative import declared_attr
 
1085
    from sqlalchemy.ext.declarative import has_inherited_table
 
1086
 
 
1087
    class Tablename(object):
 
1088
        @declared_attr
 
1089
        def __tablename__(cls):
 
1090
            if (has_inherited_table(cls) and
 
1091
                Tablename not in cls.__bases__):
 
1092
                return None
 
1093
            return cls.__name__.lower()
 
1094
 
 
1095
    class Person(Tablename, Base):
 
1096
        id = Column(Integer, primary_key=True)
 
1097
        discriminator = Column('type', String(50))
 
1098
        __mapper_args__ = {'polymorphic_on': discriminator}
 
1099
 
 
1100
    # This is single table inheritance
 
1101
    class Engineer(Person):
 
1102
        primary_language = Column(String(50))
 
1103
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
1104
 
 
1105
    # This is joined table inheritance
 
1106
    class Manager(Tablename, Person):
 
1107
        id = Column(Integer, ForeignKey('person.id'), primary_key=True)
 
1108
        preferred_recreation = Column(String(50))
 
1109
        __mapper_args__ = {'polymorphic_identity': 'engineer'}
 
1110
 
 
1111
Combining Table/Mapper Arguments from Multiple Mixins
 
1112
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
1113
 
 
1114
In the case of ``__table_args__`` or ``__mapper_args__``
 
1115
specified with declarative mixins, you may want to combine
 
1116
some parameters from several mixins with those you wish to
 
1117
define on the class iteself. The
 
1118
:class:`.declared_attr` decorator can be used
 
1119
here to create user-defined collation routines that pull
 
1120
from multiple collections::
 
1121
 
 
1122
    from sqlalchemy.ext.declarative import declared_attr
 
1123
 
 
1124
    class MySQLSettings(object):
 
1125
        __table_args__ = {'mysql_engine':'InnoDB'}
 
1126
 
 
1127
    class MyOtherMixin(object):
 
1128
        __table_args__ = {'info':'foo'}
 
1129
 
 
1130
    class MyModel(MySQLSettings, MyOtherMixin, Base):
 
1131
        __tablename__='my_model'
 
1132
 
 
1133
        @declared_attr
 
1134
        def __table_args__(cls):
 
1135
            args = dict()
 
1136
            args.update(MySQLSettings.__table_args__)
 
1137
            args.update(MyOtherMixin.__table_args__)
 
1138
            return args
 
1139
 
 
1140
        id =  Column(Integer, primary_key=True)
 
1141
 
 
1142
Creating Indexes with Mixins
 
1143
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
1144
 
 
1145
To define a named, potentially multicolumn :class:`.Index` that applies to all
 
1146
tables derived from a mixin, use the "inline" form of :class:`.Index` and
 
1147
establish it as part of ``__table_args__``::
 
1148
 
 
1149
    class MyMixin(object):
 
1150
        a =  Column(Integer)
 
1151
        b =  Column(Integer)
 
1152
 
 
1153
        @declared_attr
 
1154
        def __table_args__(cls):
 
1155
            return (Index('test_idx_%s' % cls.__tablename__, 'a', 'b'),)
 
1156
 
 
1157
    class MyModel(MyMixin, Base):
 
1158
        __tablename__ = 'atable'
 
1159
        c =  Column(Integer,primary_key=True)
 
1160
 
 
1161
Special Directives
 
1162
==================
 
1163
 
 
1164
``__declare_last__()``
 
1165
~~~~~~~~~~~~~~~~~~~~~~
 
1166
 
 
1167
The ``__declare_last__()`` hook allows definition of
 
1168
a class level function that is automatically called by the
 
1169
:meth:`.MapperEvents.after_configured` event, which occurs after mappings are
 
1170
assumed to be completed and the 'configure' step has finished::
 
1171
 
 
1172
    class MyClass(Base):
 
1173
        @classmethod
 
1174
        def __declare_last__(cls):
 
1175
            ""
 
1176
            # do something with mappings
 
1177
 
 
1178
.. versionadded:: 0.7.3
 
1179
 
 
1180
.. _declarative_abstract:
 
1181
 
 
1182
``__abstract__``
 
1183
~~~~~~~~~~~~~~~~~~~
 
1184
 
 
1185
``__abstract__`` causes declarative to skip the production
 
1186
of a table or mapper for the class entirely.  A class can be added within a
 
1187
hierarchy in the same way as mixin (see :ref:`declarative_mixins`), allowing
 
1188
subclasses to extend just from the special class::
 
1189
 
 
1190
    class SomeAbstractBase(Base):
 
1191
        __abstract__ = True
 
1192
 
 
1193
        def some_helpful_method(self):
 
1194
            ""
 
1195
 
 
1196
        @declared_attr
 
1197
        def __mapper_args__(cls):
 
1198
            return {"helpful mapper arguments":True}
 
1199
 
 
1200
    class MyMappedClass(SomeAbstractBase):
 
1201
        ""
 
1202
 
 
1203
One possible use of ``__abstract__`` is to use a distinct
 
1204
:class:`.MetaData` for different bases::
 
1205
 
 
1206
    Base = declarative_base()
 
1207
 
 
1208
    class DefaultBase(Base):
 
1209
        __abstract__ = True
 
1210
        metadata = MetaData()
 
1211
 
 
1212
    class OtherBase(Base):
 
1213
        __abstract__ = True
 
1214
        metadata = MetaData()
 
1215
 
 
1216
Above, classes which inherit from ``DefaultBase`` will use one
 
1217
:class:`.MetaData` as the registry of tables, and those which inherit from
 
1218
``OtherBase`` will use a different one. The tables themselves can then be
 
1219
created perhaps within distinct databases::
 
1220
 
 
1221
    DefaultBase.metadata.create_all(some_engine)
 
1222
    OtherBase.metadata_create_all(some_other_engine)
 
1223
 
 
1224
.. versionadded:: 0.7.3
 
1225
 
 
1226
Class Constructor
 
1227
=================
 
1228
 
 
1229
As a convenience feature, the :func:`declarative_base` sets a default
 
1230
constructor on classes which takes keyword arguments, and assigns them
 
1231
to the named attributes::
 
1232
 
 
1233
    e = Engineer(primary_language='python')
 
1234
 
 
1235
Sessions
 
1236
========
 
1237
 
 
1238
Note that ``declarative`` does nothing special with sessions, and is
 
1239
only intended as an easier way to configure mappers and
 
1240
:class:`~sqlalchemy.schema.Table` objects.  A typical application
 
1241
setup using :class:`~sqlalchemy.orm.scoped_session` might look like::
 
1242
 
 
1243
    engine = create_engine('postgresql://scott:tiger@localhost/test')
 
1244
    Session = scoped_session(sessionmaker(autocommit=False,
 
1245
                                          autoflush=False,
 
1246
                                          bind=engine))
 
1247
    Base = declarative_base()
 
1248
 
 
1249
Mapped instances then make usage of
 
1250
:class:`~sqlalchemy.orm.session.Session` in the usual way.
 
1251
 
 
1252
"""
 
1253
 
 
1254
from .api import declarative_base, synonym_for, comparable_using, \
 
1255
    instrument_declarative, ConcreteBase, AbstractConcreteBase, \
 
1256
    DeclarativeMeta, DeferredReflection, has_inherited_table,\
 
1257
    declared_attr
 
1258
 
 
1259
 
 
1260
__all__ = ['declarative_base', 'synonym_for', 'has_inherited_table',
 
1261
            'comparable_using', 'instrument_declarative', 'declared_attr',
 
1262
            'ConcreteBase', 'AbstractConcreteBase', 'DeclarativeMeta',
 
1263
            'DeferredReflection']