[Sqlalchemy-commits] [1107] sqlalchemy/trunk/examples: added backref() function, allows the creation
Brought to you by:
zzzeek
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1107] sqlalchemy/trunk/examples: added backref() function, allows the creation of a backref where you also send keyword arguments that will be placed on the relation</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1107</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-06 21:14:08 -0600 (Mon, 06 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>added backref() function, allows the creation of a backref where you also send keyword arguments that will be placed on the relation</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymapping__init__py">sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li>sqlalchemy/trunk/examples/backref/</li> <li><a href="#sqlalchemytrunkexamplesbackrefbackref_treepy">sqlalchemy/trunk/examples/backref/backref_tree.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkexamplesbackrefbackref_treepy"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/examples/backref/backref_tree.py (1106 => 1107)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/examples/backref/backref_tree.py 2006-03-06 23:15:47 UTC (rev 1106) +++ sqlalchemy/trunk/examples/backref/backref_tree.py 2006-03-07 03:14:08 UTC (rev 1107) </span><span class="lines">@@ -0,0 +1,41 @@ </span><ins>+from sqlalchemy import * +import sqlalchemy.attributes as attributes + +engine = create_engine('sqlite://', echo=True) + +class Tree(object): + def __init__(self, name='', father=None): + self.name = name + self.father = father + def __str__(self): + return '<TreeNode: %s>' % self.name + def __repr__(self): + return self.__str__() + +table = Table('tree', engine, + Column('id', Integer, primary_key=True), + Column('name', String(64), nullable=False), + Column('father_id', Integer, ForeignKey('tree.id'), nullable=True),) + +assign_mapper(Tree, table, + properties={ + # set up a backref using a string + #'father':relation(Tree, foreignkey=table.c.id,primaryjoin=table.c.father_id==table.c.id, backref='childs')}, + + # or set up using the backref() function, which allows arguments to be passed + 'childs':relation(Tree, foreignkey=table.c.father_id, primaryjoin=table.c.father_id==table.c.id, backref=backref('father', uselist=False, foreignkey=table.c.id))}, + ) + +table.create() +root = Tree('root') +child1 = Tree('child1', root) +child2 = Tree('child2', root) +child3 = Tree('child3', child1) + +objectstore.commit() + +print root.childs +print child1.childs +print child2.childs +print child2.father +print child3.father </ins></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymapping__init__py"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py (1106 => 1107)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py 2006-03-06 23:15:47 UTC (rev 1106) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py 2006-03-07 03:14:08 UTC (rev 1107) </span><span class="lines">@@ -19,7 +19,7 @@ </span><span class="cx"> from properties import * </span><span class="cx"> import mapper as mapperlib </span><span class="cx"> </span><del>-__all__ = ['relation', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer', </del><ins>+__all__ = ['relation', 'backref', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer', </ins><span class="cx"> 'mapper', 'clear_mappers', 'objectstore', 'sql', 'extension', 'class_mapper', 'object_mapper', 'MapperExtension', </span><span class="cx"> 'assign_mapper', 'cascade_mappers' </span><span class="cx"> ] </span><span class="lines">@@ -39,7 +39,12 @@ </span><span class="cx"> else: </span><span class="cx"> return EagerLoader(mapper, secondary, primaryjoin, secondaryjoin, **kwargs) </span><span class="cx"> </span><ins>+def backref(name, **kwargs): + return BackRef(name, **kwargs) + </ins><span class="cx"> def deferred(*columns, **kwargs): </span><ins>+ """returns a DeferredColumnProperty, which indicates this object attributes should only be loaded + from its corresponding table column when first accessed.""" </ins><span class="cx"> return DeferredColumnProperty(*columns, **kwargs) </span><span class="cx"> </span><span class="cx"> def mapper(class_, table=None, *args, **params): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1106 => 1107)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-06 23:15:47 UTC (rev 1106) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-07 03:14:08 UTC (rev 1107) </span><span class="lines">@@ -136,7 +136,10 @@ </span><span class="cx"> print "'use_alias' argument to relation() is deprecated. eager loads automatically alias-ize tables now." </span><span class="cx"> self.order_by = order_by </span><span class="cx"> self.attributeext=attributeext </span><del>- self.backref = backref </del><ins>+ if isinstance(backref, str): + self.backref = BackRef(backref) + else: + self.backref = backref </ins><span class="cx"> self.is_backref = is_backref </span><span class="cx"> </span><span class="cx"> def copy(self): </span><span class="lines">@@ -197,27 +200,13 @@ </span><span class="cx"> # if a backref name is defined, set up an extension to populate </span><span class="cx"> # attributes in the other direction </span><span class="cx"> if self.backref is not None: </span><del>- self.attributeext = attributes.GenericBackrefExtension(self.backref) </del><ins>+ self.attributeext = self.backref.get_extension() </ins><span class="cx"> </span><span class="cx"> # set our class attribute </span><span class="cx"> self._set_class_attribute(parent.class_, key) </span><span class="cx"> </span><span class="cx"> if self.backref is not None: </span><del>- # try to set a LazyLoader on our mapper referencing the parent mapper - if not self.mapper.props.has_key(self.backref): - if self.secondaryjoin is not None: - # if setting up a backref to a many-to-many, reverse the order - # of the "primary" and "secondary" joins - pj = self.secondaryjoin - sj = self.primaryjoin - else: - pj = self.primaryjoin - sj = None - self.mapper.add_property(self.backref, LazyLoader(self.parent, self.secondary, pj, sj, 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 </del><ins>+ self.backref.compile(self) </ins><span class="cx"> elif not objectstore.global_attributes.is_class_managed(parent.class_, key): </span><span class="cx"> raise ArgumentError("Non-primary property created for attribute '%s' on class '%s', but that attribute is not managed! Insure that the primary mapper for this class defines this property" % (key, parent.class_.__name__)) </span><span class="cx"> </span><span class="lines">@@ -816,7 +805,33 @@ </span><span class="cx"> kwargs = util.constructor_args(oldprop) </span><span class="cx"> mapper.set_property(key, class_(**kwargs )) </span><span class="cx"> </span><del>- </del><ins>+class BackRef(object): + """stores the name of a backreference property as well as a relation (PropertyLoader), + used to construct more customized backrefs""" + def __init__(self, key, **kwargs): + self.key = key + self.kwargs = kwargs + def compile(self, prop): + # try to set a LazyLoader on our mapper referencing the parent mapper + if not prop.mapper.props.has_key(self.key): + if prop.secondaryjoin is not None: + # if setting up a backref to a many-to-many, reverse the order + # of the "primary" and "secondary" joins + pj = prop.secondaryjoin + sj = prop.primaryjoin + else: + pj = prop.primaryjoin + sj = None + relation = LazyLoader(prop.parent, prop.secondary, pj, sj, backref=prop.key, is_backref=True, **self.kwargs) + prop.mapper.add_property(self.key, relation); + else: + # else set one of us as the "backreference" + if not prop.mapper.props[self.key].is_backref: + prop.is_backref=True + + def get_extension(self): + return attributes.GenericBackrefExtension(self.key) + </ins><span class="cx"> class EagerLazyOption(GenericOption): </span><span class="cx"> """an option that switches a PropertyLoader to be an EagerLoader or LazyLoader""" </span><span class="cx"> def __init__(self, key, toeager = True, **kwargs): </span></span></pre> </div> </div> </body> </html> |