1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
"""Define attributes on ORM-mapped classes that have 'hybrid' behavior.
'hybrid' means the attribute has distinct behaviors defined at the
class level and at the instance level.
Consider a table `interval` as below::
from sqlalchemy import MetaData, Table, Column, Integer
from sqlalchemy.orm import mapper, create_session
engine = create_engine('sqlite://')
metadata = MetaData()
interval_table = Table('interval', metadata,
Column('id', Integer, primary_key=True),
Column('start', Integer, nullable=False),
Column('end', Integer, nullable=False))
metadata.create_all(engine)
We can define higher level functions on mapped classes that produce SQL
expressions at the class level, and Python expression evaluation at the
instance level. Below, each function decorated with :func:`hybrid.method`
or :func:`hybrid.property` may receive ``self`` as an instance of the class,
or as the class itself::
# A base class for intervals
from sqlalchemy.orm import hybrid
class Interval(object):
def __init__(self, start, end):
self.start = start
self.end = end
@hybrid.property
def length(self):
return self.end - self.start
@hybrid.method
def contains(self,point):
return (self.start <= point) & (point < self.end)
@hybrid.method
def intersects(self, other):
return (self.start < other.end) & (self.end > other.start)
mapper(Interval1, interval_table1)
session = sessionmaker(engine)()
session.add_all(
[Interval1(1,4), Interval1(3,15), Interval1(11,16)]
)
intervals =
for interval in intervals:
session.add(interval)
session.add(Interval2(interval.start, interval.length))
session.commit()
### TODO ADD EXAMPLES HERE AND STUFF THIS ISN'T FINISHED ###
"""
from sqlalchemy import util
from sqlalchemy.orm import attributes, interfaces
class method(object):
def __init__(self, func, expr=None):
self.func = func
self.expr = expr or func
def __get__(self, instance, owner):
if instance is None:
return new.instancemethod(self.expr, owner, owner.__class__)
else:
return new.instancemethod(self.func, instance, owner)
def expression(self, expr):
self.expr = expr
return self
class property_(object):
def __init__(self, fget, fset=None, fdel=None, expr=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
self.expr = expr or fget
util.update_wrapper(self, fget)
def __get__(self, instance, owner):
if instance is None:
return self.expr(owner)
else:
return self.fget(instance)
def __set__(self, instance, value):
self.fset(instance, value)
def __delete__(self, instance):
self.fdel(instance)
def setter(self, fset):
self.fset = fset
return self
def deleter(self, fdel):
self.fdel = fdel
return self
def expression(self, expr):
self.expr = expr
return self
def comparator(self, comparator):
proxy_attr = attributes.\
create_proxied_attribute(self)
def expr(owner):
return proxy_attr(self.__name__, self, comparator(owner))
self.expr = expr
return self
class Comparator(interfaces.PropComparator):
def __init__(self, expression):
self.expression = expression
def __clause_element__(self):
expr = self.expression
while hasattr(expr, '__clause_element__'):
expr = expr.__clause_element__()
return expr
def adapted(self, adapter):
# interesting....
return self
def hybrid_and(self):
if isinstance(self, type):
return expression.and_
else:
return operator.and_
|