Fixed #12049 - LazyObject-wrapped User breaks queries in template tags

Thanks to chipx86 for the report and patch.



git-svn-id: http://code.djangoproject.com/svn/django/trunk@11634 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2009-10-19 21:13:22 +00:00
parent cb7a3262b5
commit 22be3d7612
2 changed files with 33 additions and 0 deletions

View File

@ -297,6 +297,11 @@ class SimpleLazyObject(LazyObject):
def __init__(self, func): def __init__(self, func):
""" """
Pass in a callable that returns the object to be wrapped. Pass in a callable that returns the object to be wrapped.
If copies are made of the resulting SimpleLazyObject, which can happen
in various circumstances within Django, then you must ensure that the
callable can be safely run more than once and will return the same
value.
""" """
self.__dict__['_setupfunc'] = func self.__dict__['_setupfunc'] = func
# For some reason, we have to inline LazyObject.__init__ here to avoid # For some reason, we have to inline LazyObject.__init__ here to avoid
@ -307,5 +312,14 @@ class SimpleLazyObject(LazyObject):
if self._wrapped is None: self._setup() if self._wrapped is None: self._setup()
return str(self._wrapped) return str(self._wrapped)
def __deepcopy__(self, memo):
if self._wrapped is None:
result = self.__class__(self._setupfunc)
memo[id(self)] = result
return result
else:
import copy
return copy.deepcopy(self._wrapped, memo)
def _setup(self): def _setup(self):
self._wrapped = self._setupfunc() self._wrapped = self._setupfunc()

View File

@ -3,6 +3,8 @@ Tests for Django's bundled context processors.
""" """
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import Group
from django.db.models import Q
from django.test import TestCase from django.test import TestCase
from django.template import Template from django.template import Template
@ -81,3 +83,20 @@ class AuthContextProcessorTests(TestCase):
self.assertContains(response, "username: super") self.assertContains(response, "username: super")
# bug #12037 is tested by the {% url %} in the template: # bug #12037 is tested by the {% url %} in the template:
self.assertContains(response, "url: /userpage/super/") self.assertContains(response, "url: /userpage/super/")
# See if this object can be used for queries where a Q() comparing
# a user can be used with another Q() (in an AND or OR fashion).
# This simulates what a template tag might do with the user from the
# context. Note that we don't need to execute a query, just build it.
#
# The failure case (bug #12049) on Python 2.4 with a LazyObject-wrapped
# User is a fatal TypeError: "function() takes at least 2 arguments
# (0 given)" deep inside deepcopy().
#
# Python 2.5 and 2.6 succeeded, but logged internally caught exception
# spew:
#
# Exception RuntimeError: 'maximum recursion depth exceeded while
# calling a Python object' in <type 'exceptions.AttributeError'>
# ignored"
query = Q(user=response.context['user']) & Q(someflag=True)