summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/mapping/properties.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2005-12-09 05:08:51 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2005-12-09 05:08:51 +0000
commit69ad2955bdb33eb45939a01d95bcff240a2d9fb6 (patch)
tree8e285e2c1850a94ae3e44a7fe118f86bf8ff3448 /lib/sqlalchemy/mapping/properties.py
parentddf671347205aae40e501c5533c2dd7a94a6a3a1 (diff)
downloadsqlalchemy-69ad2955bdb33eb45939a01d95bcff240a2d9fb6.tar.gz
build in 'backref' property argument
Diffstat (limited to 'lib/sqlalchemy/mapping/properties.py')
-rw-r--r--lib/sqlalchemy/mapping/properties.py48
1 files changed, 39 insertions, 9 deletions
diff --git a/lib/sqlalchemy/mapping/properties.py b/lib/sqlalchemy/mapping/properties.py
index 4b82157d3..08897f2e6 100644
--- a/lib/sqlalchemy/mapping/properties.py
+++ b/lib/sqlalchemy/mapping/properties.py
@@ -21,6 +21,7 @@ import sqlalchemy.sql as sql
import sqlalchemy.schema as schema
import sqlalchemy.engine as engine
import sqlalchemy.util as util
+import sqlalchemy.attributes as attributes
import mapper
import objectstore
import random
@@ -56,13 +57,13 @@ class ColumnProperty(MapperProperty):
mapper.ColumnProperty = ColumnProperty
class PropertyLoader(MapperProperty):
- LEFT = 0
- RIGHT = 1
- CENTER = 2
+ LEFT = 0 # one-to-many
+ RIGHT = 1 # many-to-one
+ CENTER = 2 # many-to-many
"""describes an object property that holds a single item or list of items that correspond
to a related database table."""
- def __init__(self, argument, secondary, primaryjoin, secondaryjoin, foreignkey=None, uselist=None, private=False, live=False, isoption=False, association=None, selectalias=None, order_by=None, attributeext=None):
+ def __init__(self, argument, secondary, primaryjoin, secondaryjoin, foreignkey=None, uselist=None, private=False, live=False, isoption=False, association=None, selectalias=None, order_by=None, attributeext=None, backref=None, is_backref=False):
self.uselist = uselist
self.argument = argument
self.secondary = secondary
@@ -76,6 +77,8 @@ class PropertyLoader(MapperProperty):
self.selectalias = selectalias
self.order_by=util.to_list(order_by)
self.attributeext=attributeext
+ self.backref = backref
+ self.is_backref = is_backref
self._hash_key = "%s(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.__class__.__name__, hash_key(self.argument), hash_key(secondary), hash_key(primaryjoin), hash_key(secondaryjoin), hash_key(foreignkey), repr(uselist), repr(private), hash_key(self.order_by))
def _copy(self):
@@ -126,10 +129,31 @@ class PropertyLoader(MapperProperty):
self.uselist = True
self._compile_synchronizers()
-
+
+ # primary property handler, set up class attributes
if self._is_primary():
+ # if a backref name is defined, set up an extension to populate
+ # attributes in the other direction
+ if self.backref is not None:
+ if self.direction == PropertyLoader.LEFT:
+ self.attributeext = attributes.OTMBackrefExtension(self.backref)
+ elif self.direction == PropertyLoader.RIGHT:
+ self.attributeext = attributes.MTOBackrefExtension(self.backref)
+ else:
+ self.attributeext = attributes.ListBackrefExtension(self.backref)
+
+ # set our class attribute
self._set_class_attribute(parent.class_, key)
-
+
+ if self.backref is not None:
+ # try to set a LazyLoader on our mapper referencing the parent mapper
+ if not self.mapper.props.has_key(self.backref):
+ self.mapper.add_property(self.backref, LazyLoader(self.parent, self.secondary, self.primaryjoin, self.secondaryjoin, backref=self.key, is_backref=True));
+ else:
+ # else set one of us as the "backreference"
+ if not self.mapper.props[self.backref].is_backref:
+ self.is_backref=True
+
def _is_primary(self):
"""a return value of True indicates we are the primary PropertyLoader for this loader's
attribute on our mapper's class. It means we can set the object's attribute behavior
@@ -277,6 +301,11 @@ class PropertyLoader(MapperProperty):
# or delete any objects, but just marks a dependency on the two
# related mappers. its dependency processor then populates the
# association table.
+
+ if self.is_backref:
+ # if we are the "backref" half of a two-way backref
+ # relationship, let the other mapper handle inserting the rows
+ return
stub = PropertyLoader.MapperStub()
uowcommit.register_dependency(self.parent, stub)
uowcommit.register_dependency(self.mapper, stub)
@@ -674,10 +703,11 @@ class EagerLazyOption(MapperOption):
else:
class_ = LazyLoader
- for arg in ('primaryjoin', 'secondaryjoin', 'foreignkey', 'uselist', 'private', 'live', 'isoption', 'association', 'selectalias', 'order_by', 'attributeext'):
- self.kwargs.setdefault(arg, getattr(oldprop, arg))
+ # create a clone of the class using mostly the arguments from the original
self.kwargs['isoption'] = True
- mapper.set_property(key, class_(submapper, oldprop.secondary, **self.kwargs ))
+ self.kwargs['argument'] = submapper
+ kwargs = util.constructor_args(oldprop, **self.kwargs)
+ mapper.set_property(key, class_(**kwargs ))
class Aliasizer(sql.ClauseVisitor):
"""converts a table instance within an expression to be an alias of that table."""