#15062: r14389 breaks getattr on Manager subclasses
---------------------------------------------------+------------------------
Reporter: clelland | Owner: nobody
Status: reopened | Milestone: 1.3
Component: Database layer (models, ORM) | Version: SVN
Resolution: | Keywords: regression
blocker
Stage: Accepted | Has_patch: 0
Needs_docs: 0 | Needs_tests: 0
Needs_better_patch: 0 |
---------------------------------------------------+------------------------
Comment (by lrekucki):
From what I managed to debug, the recursion starts in call to
{{{self.db_manager(db)}}} which tries to {{{copy()}}} the manager
instance.
Your custom manager intercepts calls (and hasattr checks) of
{{{__getstate__}}} and {{{__setstate__}}} to a freshly created QuerySet
instance. Python tries to use those method to copy the manager. A
{{{hasattr()}}} check for {{{__setstate__}}} is caught by
{{{__getattr__}}} which executes {{{self.get_query_set()}}}. But that
assumes that the manager instance has gone through proper
initialization... so a lookup for a field like {{{self._db}}} fails and
hits the {{{__getattr__}}}. Boom!.
I'm in favour of marking this as invalid, as you shouldn't be passing
magic methods like {{{__getstate__}}} to other objects. Personally, I
wouldn't pass anything marked as private, like this:
{{{
def __getattr__(self, attr, *args):
if attr.startswith("_"): # or at least "__"
raise AttributeError
return getattr(self.get_query_set(), attr, *args)
}}}
With the code above, the testcase you provided works fine.
--
Ticket URL: <http://code.djangoproject.com/ticket/15062#comment:6>
Django <http://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en.