#15062: r14389 breaks getattr on Manager subclasses
------------------------------------------+---------------------------------
 Reporter:  clelland                      |       Owner:  nobody    
   Status:  new                           |   Milestone:  1.3       
Component:  Database layer (models, ORM)  |     Version:  SVN       
 Keywords:                                |       Stage:  Unreviewed
Has_patch:  0                             |  
------------------------------------------+---------------------------------
 I've been using Simon Willison's [http://djangosnippets.org/snippets/734/
 QuerySetManager] pattern for a while now, and since upgrading to Django
 1.2.4, it has been breaking when I try to call a method on a
 !RelatedManager constructed from it.

 There was a change in r14389 (r14390 in the 1.2.X branch) which causes
 this code to break -- where there was a simple delegation before from the
 !RelatedManager to the !QuerySetManager to the model, there now appears to
 be an infinite recursion, with the !RelatedManager and !QuerySetManager
 trying to call each other's get_query_set methods.

 !QuerySetManager is just a simple subclass of `django.db.models.Manager`,
 which overrides `__getattr__` to proxy custom method calls on the manager
 to a class attached to the underlying model.

 The simplest test case I can get to reproduce this problem looks like
 this:

 {{{
 from django.db import models
 from django.contrib.auth.models import User
 from helpers import QuerySetManager

 class TestModel(models.Model):
    user = models.ForeignKey(User)
    string = models.CharField(max_length=64, null=True, blank=True)
    objects = QuerySetManager()
    class QuerySet(models.query.QuerySet):
        pass
 }}}

 Using it gives a traceback like this:

 {{{
 >>> user = User.objects.get(username='testuser')
 >>> user.testmodel_set.create(string="test")
 Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    user.testmodel_set.create(string="test")
  File "/Users/ian/.virtualenvs/testcode/lib/python2.6/site-
 packages/django/db/models/fields/related.py", line 423, in create
    return super(RelatedManager, self.db_manager(db)).create(**kwargs)
  File "/Users/ian/.virtualenvs/egather/lib/python2.6/site-
 packages/django/db/models/manager.py", line 138, in create
    return self.get_query_set().create(**kwargs)
  File "/Users/ian/.virtualenvs/testcode/lib/python2.6/site-
 packages/django/db/models/fields/related.py", line 410, in get_query_set
    return
 superclass.get_query_set(self).using(db).filter(**(self.core_filters))
  File "/Users/ian/Code/Tests/related_test/test_app/models.py", line 17, in
 __getattr__
    return getattr(self.get_query_set(), attr, *args)
  File "/Users/ian/.virtualenvs/testcode/lib/python2.6/site-
 packages/django/db/models/fields/related.py", line 410, in get_query_set
    return
 superclass.get_query_set(self).using(db).filter(**(self.core_filters))
  File "/Users/ian/Code/Tests/related_test/test_app/models.py", line 17, in
 __getattr__
    return getattr(self.get_query_set(), attr, *args)
  File "/Users/ian/.virtualenvs/testcode/lib/python2.6/site-
 packages/django/db/models/fields/related.py", line 410, in get_query_set
    return
 superclass.get_query_set(self).using(db).filter(**(self.core_filters))
  File "/Users/ian/Code/Tests/related_test/test_app/models.py", line 17, in
 __getattr__
    return getattr(self.get_query_set(), attr, *args)
  File "/Users/ian/.virtualenvs/testcode/lib/python2.6/site-
 packages/django/db/models/fields/related.py", line 410, in get_query_set
    return
 superclass.get_query_set(self).using(db).filter(**(self.core_filters))
  File "/Users/ian/Code/Tests/related_test/test_app/models.py", line 17, in
 __getattr__
    return getattr(self.get_query_set(), attr, *args)
 ...
 Lots snipped
 ...
  File "/Users/ian/.virtualenvs/egather/lib/python2.6/site-
 packages/django/db/models/fields/related.py", line 410, in get_query_set
    return
 superclass.get_query_set(self).using(db).filter(**(self.core_filters))
  File "/Users/ian/Code/Tests/related_test/test_app/models.py", line 14, in
 get_query_set
    return self.model.QuerySet(self.model)
  File "/Users/ian/.virtualenvs/testcode/lib/python2.6/site-
 packages/django/db/models/query.py", line 33, in __init__
    self.query = query or sql.Query(self.model)
  File "/Users/ian/.virtualenvs/testcode/lib/python2.6/site-
 packages/django/db/models/sql/query.py", line 138, in __init__
    self.aggregates = SortedDict() # Maps alias -> SQL aggregate function
  File "/Users/ian/.virtualenvs/testcode/lib/python2.6/site-
 packages/django/utils/datastructures.py", line 97, in __init__
    super(SortedDict, self).__init__(data)
 RuntimeError: maximum recursion depth exceeded while calling a Python
 object
 }}}

-- 
Ticket URL: <http://code.djangoproject.com/ticket/15062>
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 django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to