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

« back to all changes in this revision

Viewing changes to examples/poly_assoc/poly_assoc_generic.py

  • Committer: Bazaar Package Importer
  • Author(s): Piotr Ożarowski
  • Date: 2011-08-01 23:18:16 UTC
  • mfrom: (1.4.15 upstream) (16.1.14 experimental)
  • Revision ID: james.westby@ubuntu.com-20110801231816-6lx797pi3q1fpqst
Tags: 0.7.2-1
* New upstream release
* Bump minimum required python-mako version to 0.4.1 (closes: 635898)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
"polymorphic" associations, ala SQLAlchemy.
3
 
 
4
 
This example generalizes the function in poly_assoc_pk.py into a function
5
 
"association" which creates a new polymorphic association "interface".
6
 
"""
7
 
 
8
 
from sqlalchemy import MetaData, Table, Column, Integer, String, \
9
 
    ForeignKey
10
 
from sqlalchemy.orm import mapper, relationship, sessionmaker, \
11
 
    class_mapper
12
 
 
13
 
metadata = MetaData('sqlite://')
14
 
 
15
 
def association(cls, table):
16
 
    """create an association 'interface'."""
17
 
 
18
 
    interface_name = table.name
19
 
    attr_name = "%s_rel" % interface_name
20
 
 
21
 
    metadata = table.metadata
22
 
    association_table = Table("%s_associations" % interface_name, metadata,
23
 
        Column('assoc_id', Integer, primary_key=True),
24
 
        Column('type', String(50), nullable=False)
25
 
    )
26
 
 
27
 
    class GenericAssoc(object):
28
 
        def __init__(self, name):
29
 
            self.type = name
30
 
 
31
 
    def interface(cls, name, uselist=True):
32
 
 
33
 
        mapper = class_mapper(cls)
34
 
        table = mapper.local_table
35
 
        mapper.add_property(attr_name, 
36
 
                            relationship(GenericAssoc, 
37
 
                                    backref='_backref_%s' % table.name)
38
 
                            )
39
 
 
40
 
        if uselist:
41
 
            # list based property decorator
42
 
            def get(self):
43
 
                if getattr(self, attr_name) is None:
44
 
                    setattr(self, attr_name, GenericAssoc(table.name))
45
 
                return getattr(self, attr_name).targets
46
 
            setattr(cls, name, property(get))
47
 
        else:
48
 
            # scalar based property decorator
49
 
            def get(self):
50
 
                return getattr(self, attr_name).targets[0]
51
 
            def set(self, value):
52
 
                if getattr(self, attr_name) is None:
53
 
                    setattr(self, attr_name, GenericAssoc(table.name))
54
 
                getattr(self, attr_name).targets = [value]
55
 
            setattr(cls, name, property(get, set))
56
 
 
57
 
    @property
58
 
    def member(self):
59
 
        return getattr(self.association, 
60
 
                    '_backref_%s' % self.association.type)
61
 
 
62
 
    setattr(cls, 'member', member)
63
 
 
64
 
    mapper(GenericAssoc, association_table, properties={
65
 
        'targets':relationship(cls, backref='association'),
66
 
    })
67
 
 
68
 
    return interface
69
 
 
70
 
 
71
 
#######
72
 
# addresses table
73
 
 
74
 
addresses = Table("addresses", metadata,
75
 
    Column('id', Integer, primary_key=True),
76
 
    Column('assoc_id', Integer, ForeignKey('addresses_associations.assoc_id')),
77
 
    Column('street', String(100)),
78
 
    Column('city', String(50)),
79
 
    Column('country', String(50))
80
 
    )
81
 
 
82
 
class Address(object):
83
 
    pass
84
 
 
85
 
# create "addressable" association
86
 
addressable = association(Address, addresses)
87
 
 
88
 
mapper(Address, addresses)
89
 
 
90
 
 
91
 
######
92
 
# sample # 1, users
93
 
 
94
 
users = Table("users", metadata,
95
 
    Column('id', Integer, primary_key=True),
96
 
    Column('name', String(50), nullable=False),
97
 
    Column('assoc_id', Integer, ForeignKey('addresses_associations.assoc_id'))
98
 
    )
99
 
 
100
 
class User(object):
101
 
    pass
102
 
 
103
 
mapper(User, users)
104
 
 
105
 
# use the association
106
 
addressable(User, 'addresses', uselist=True)
107
 
 
108
 
######
109
 
# sample # 2, orders
110
 
 
111
 
orders = Table("orders", metadata,
112
 
    Column('id', Integer, primary_key=True),
113
 
    Column('description', String(50), nullable=False),
114
 
    Column('assoc_id', Integer, ForeignKey('addresses_associations.assoc_id'))
115
 
    )
116
 
 
117
 
class Order(object):
118
 
    pass
119
 
 
120
 
mapper(Order, orders)
121
 
addressable(Order, 'address', uselist=False)
122
 
 
123
 
######
124
 
# use it !
125
 
metadata.create_all()
126
 
 
127
 
u1 = User()
128
 
u1.name = 'bob'
129
 
 
130
 
o1 = Order()
131
 
o1.description = 'order 1'
132
 
 
133
 
a1 = Address()
134
 
u1.addresses.append(a1)
135
 
a1.street = '123 anywhere street'
136
 
 
137
 
a2 = Address()
138
 
u1.addresses.append(a2)
139
 
a2.street = '345 orchard ave'
140
 
 
141
 
o1.address = Address()
142
 
o1.address.street = '444 park ave.'
143
 
 
144
 
sess = sessionmaker()()
145
 
sess.add(u1)
146
 
sess.add(o1)
147
 
sess.commit()
148
 
 
149
 
# query objects, get their addresses
150
 
 
151
 
bob = sess.query(User).filter_by(name='bob').one()
152
 
assert [s.street for s in bob.addresses] == \
153
 
            ['123 anywhere street', '345 orchard ave']
154
 
 
155
 
order = sess.query(Order).filter_by(description='order 1').one()
156
 
assert order.address.street == '444 park ave.'
157
 
 
158
 
# query from Address to members
159
 
 
160
 
for address in sess.query(Address).all():
161
 
    print "Street", address.street, "Member", address.member