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

« back to all changes in this revision

Viewing changes to examples/generic_associations/discriminator_on_association.py

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski
  • Date: 2013-10-28 22:29:40 UTC
  • mfrom: (1.4.24)
  • Revision ID: package-import@ubuntu.com-20131028222940-wvyqffl4g617caun
Tags: 0.8.3-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
The HasAddresses mixin will provide a relationship
4
4
to the fixed Address table based on a fixed association table.
5
5
 
6
 
The association table will also contain a "discriminator"
 
6
The association table contains a "discriminator"
7
7
which determines what type of parent object associates to the
8
 
Address row.
 
8
Address row.  SQLAlchemy's single-table-inheritance feature is used
 
9
to target different association types.
9
10
 
10
11
This is a "polymorphic association".   Even though a "discriminator"
11
12
that refers to a particular table is present, the extra association
12
13
table is used so that traditional foreign key constraints may be used.
13
14
 
14
 
This configuration has the advantage that a fixed set of tables
15
 
are used, with no extra-table-per-parent needed.   The individual
16
 
Address record can also locate its parent with no need to scan
17
 
amongst many tables.
 
15
This configuration attempts to simulate a so-called "generic foreign key"
 
16
as closely as possible without actually foregoing the use of real
 
17
foreign keys.   Unlike table-per-related and table-per-association,
 
18
it uses a fixed number of tables to serve any number of potential parent
 
19
objects, but is also slightly more complex.
18
20
 
19
21
"""
20
 
from sqlalchemy.ext.declarative import declarative_base, declared_attr
 
22
from sqlalchemy.ext.declarative import as_declarative, declared_attr
21
23
from sqlalchemy import create_engine, Integer, Column, \
22
 
                    String, ForeignKey, Table
 
24
                    String, ForeignKey
23
25
from sqlalchemy.orm import Session, relationship, backref
24
26
from sqlalchemy.ext.associationproxy import association_proxy
25
27
 
 
28
@as_declarative()
26
29
class Base(object):
27
30
    """Base class which provides automated table name
28
31
    and surrogate primary key column.
32
35
    def __tablename__(cls):
33
36
        return cls.__name__.lower()
34
37
    id = Column(Integer, primary_key=True)
35
 
Base = declarative_base(cls=Base)
36
38
 
37
39
class AddressAssociation(Base):
38
40
    """Associates a collection of Address objects
41
43
    """
42
44
    __tablename__ = "address_association"
43
45
 
44
 
    @classmethod
45
 
    def creator(cls, discriminator):
46
 
        """Provide a 'creator' function to use with
47
 
        the association proxy."""
48
 
 
49
 
        return lambda addresses:AddressAssociation(
50
 
                                addresses=addresses,
51
 
                                discriminator=discriminator)
52
 
 
53
46
    discriminator = Column(String)
54
47
    """Refers to the type of parent."""
55
48
 
56
 
    @property
57
 
    def parent(self):
58
 
        """Return the parent object."""
59
 
        return getattr(self, "%s_parent" % self.discriminator)
 
49
    __mapper_args__ = {"polymorphic_on": discriminator}
60
50
 
61
51
class Address(Base):
62
52
    """The Address class.
65
55
    single table.
66
56
 
67
57
    """
68
 
    association_id = Column(Integer,
69
 
                        ForeignKey("address_association.id")
70
 
                    )
 
58
    association_id = Column(Integer, ForeignKey("address_association.id"))
71
59
    street = Column(String)
72
60
    city = Column(String)
73
61
    zip = Column(String)
74
 
    association = relationship(
75
 
                    "AddressAssociation",
76
 
                    backref="addresses")
 
62
    association = relationship("AddressAssociation", backref="addresses")
77
63
 
78
64
    parent = association_proxy("association", "parent")
79
65
 
89
75
    """
90
76
    @declared_attr
91
77
    def address_association_id(cls):
92
 
        return Column(Integer,
93
 
                                ForeignKey("address_association.id"))
 
78
        return Column(Integer, ForeignKey("address_association.id"))
94
79
 
95
80
    @declared_attr
96
81
    def address_association(cls):
97
 
        discriminator = cls.__name__.lower()
98
 
        cls.addresses= association_proxy(
 
82
        name = cls.__name__
 
83
        discriminator = name.lower()
 
84
 
 
85
        assoc_cls = type(
 
86
                        "%sAddressAssociation" % name,
 
87
                        (AddressAssociation, ),
 
88
                        dict(
 
89
                            __mapper_args__={
 
90
                                "polymorphic_identity": discriminator
 
91
                            }
 
92
                        )
 
93
                    )
 
94
 
 
95
        cls.addresses = association_proxy(
99
96
                    "address_association", "addresses",
100
 
                    creator=AddressAssociation.creator(discriminator)
 
97
                    creator=lambda addresses: assoc_cls(addresses=addresses)
101
98
                )
102
 
        return relationship("AddressAssociation",
103
 
                    backref=backref("%s_parent" % discriminator,
104
 
                                        uselist=False))
 
99
        return relationship(assoc_cls,
 
100
                    backref=backref("parent", uselist=False))
105
101
 
106
102
 
107
103
class Customer(HasAddresses, Base):
145
141
for customer in session.query(Customer):
146
142
    for address in customer.addresses:
147
143
        print address
148
 
        print address.parent
 
 
b'\\ No newline at end of file'
 
144
        print address.parent