Hey,

Michael Bayer wrote:
> Martijn Faassen wrote:
>> Michael Bayer wrote:
>>> subclass RelationProperty fine, but don't get involved with overriding
>>> its
>>> internal _xxx methods.
>> So:
>>
>> Override do_init() completely (not calling the super do_init()).
> 
> no, call do_init().
> 
> def do_init(self):
>     self.primaryjoin = figure_out_my_primary_join()
>     super(RelationProperty, self).do_init()

Can't do that as parent and target haven't been figured out yet, which 
_determine_joins and custom joins need. That happens here somewhere:

    self._get_target()
    self._process_dependent_arguments()

>> Problem: the backref will already have been set up, and this will not
>> get the custom arguments.
>
> the backref you can roll without using backref().   set up your custom
> relation() on the other side and then establish the two-way communication
> using the "back_populates" argument on both relations. 
> http://www.sqlalchemy.org/trac/browser/sqlalchemy/trunk/test/orm/test_relationships.py#L803
> is an example.

That's nice, but my goal is to make these custom relations work in the 
same way as they do now, with an additional criterion. The current 
SQLAlchemy backref story works just fine, and I don't want to make my 
users suddenly switch to a more verbose mechanism. The goal is to allow 
the creation of these special relations without extra verbosity.

>> It's pretty involved, ugly, and fragile. It'd be nicer if there was a
>> way to do this generically, as I just want to add a custom condition to
>> the automatically set up primary...
> 
> I *really* try to avoid adding new arguments and flags as quick solutions
> to single-user use cases, unless there is truly no other way to accomplish
> the desired goal.  the "back_populates" argument is an example of opening
> up the mechanics of "backref" in a more generalized way.

I'm not asking for new arguments and flags. I'm just pointing out that 
RelationProperty is *really* hard to subclass. It might be time to start 
thinking about refactoring it, just to make it a bit easier to 
comprehend what is going on. As a side-effect it might make it a bit 
easier to subclass for my purposes. :)

Here's what works, but it's really ugly as I have to override a private 
method, and re-assign to the backref attribute to make backrefs work 
properly:

class MyRelationProperty(RelationProperty):
     def extra_relation_condition(self):
         raise NotImplementedError
         # for instance:
         # return self.parent.c.foo == 3

     def _determine_joins(self):
         super(MyRelationProperty, self)._determine_joins()
         # XXX is orm_deannotate really needed? codepath in
         # RelationProperty suggests it is run...
         self.primaryjoin = _orm_deannotate(
             and_(self.primaryjoin,
                  self.extra_relation_condition()))
         if self.backref is not None:
             self.backref = BackRef(self.backref.key,
                                    primaryjoin=self.primaryjoin,
                                    secondaryjoin=self.secondaryjoin,
                                    passive_updates=self.passive_updates)

There are certainly issues here; I don't know whether all this works 
properly for many to many relations for instance. Probably not.

This way I can reuse exactly what _determine_joins has come up with, 
immediately at the point where this is relevant. I have to stuff in a 
new backref too, as the backref is already set up way earlier, in 
__init__, which is a monster to override.

Regards,

Martijn


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to