Fixes #31877 -- Used lazy() for TemplateView kwarg deprecation warning.

SimpleLazyObjects cause a crash when filtering.

Thanks Tim L. White for the report.
Regression in 4ed534758c.
This commit is contained in:
Adam Johnson 2020-08-12 12:19:46 +01:00 committed by Mariusz Felisiak
parent 8954f255bb
commit 20799cc0a6
3 changed files with 26 additions and 5 deletions

View File

@ -11,7 +11,7 @@ from django.template.response import TemplateResponse
from django.urls import reverse from django.urls import reverse
from django.utils.decorators import classonlymethod from django.utils.decorators import classonlymethod
from django.utils.deprecation import RemovedInDjango40Warning from django.utils.deprecation import RemovedInDjango40Warning
from django.utils.functional import SimpleLazyObject from django.utils.functional import lazy
logger = logging.getLogger('django.request') logger = logging.getLogger('django.request')
@ -169,7 +169,6 @@ def _wrap_url_kwargs_with_deprecation_warning(url_kwargs):
context_kwargs = {} context_kwargs = {}
for key, value in url_kwargs.items(): for key, value in url_kwargs.items():
# Bind into function closure. # Bind into function closure.
@SimpleLazyObject
def access_value(key=key, value=value): def access_value(key=key, value=value):
warnings.warn( warnings.warn(
'TemplateView passing URL kwargs to the context is ' 'TemplateView passing URL kwargs to the context is '
@ -178,7 +177,7 @@ def _wrap_url_kwargs_with_deprecation_warning(url_kwargs):
RemovedInDjango40Warning, stacklevel=2, RemovedInDjango40Warning, stacklevel=2,
) )
return value return value
context_kwargs[key] = access_value context_kwargs[key] = lazy(access_value, type(value))()
return context_kwargs return context_kwargs

View File

@ -25,3 +25,7 @@ Bugfixes
:meth:`~django.db.models.query.QuerySet.select_for_update()`. When using :meth:`~django.db.models.query.QuerySet.select_for_update()`. When using
related fields pointing to a proxy model in the ``of`` argument, the related fields pointing to a proxy model in the ``of`` argument, the
corresponding model was not locked (:ticket:`31866`). corresponding model was not locked (:ticket:`31866`).
* Fixed a regression in Django 3.1 that caused a crash when passing deprecated
keyword arguments to a queryset in ``TemplateView.get_context_data()``
(:ticket:`31877`).

View File

@ -3,7 +3,8 @@ import time
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponse from django.http import HttpResponse
from django.test import ( from django.test import (
RequestFactory, SimpleTestCase, ignore_warnings, override_settings, RequestFactory, SimpleTestCase, TestCase, ignore_warnings,
override_settings,
) )
from django.test.utils import require_jinja2 from django.test.utils import require_jinja2
from django.urls import resolve from django.urls import resolve
@ -11,6 +12,7 @@ from django.utils.deprecation import RemovedInDjango40Warning
from django.views.generic import RedirectView, TemplateView, View from django.views.generic import RedirectView, TemplateView, View
from . import views from . import views
from .models import Artist
class SimpleView(View): class SimpleView(View):
@ -571,7 +573,9 @@ class SingleObjectTemplateResponseMixinTest(SimpleTestCase):
@override_settings(ROOT_URLCONF='generic_views.urls') @override_settings(ROOT_URLCONF='generic_views.urls')
class DeprecationTests(SimpleTestCase): class DeprecationTests(TestCase):
rf = RequestFactory()
@ignore_warnings(category=RemovedInDjango40Warning) @ignore_warnings(category=RemovedInDjango40Warning)
def test_template_params(self): def test_template_params(self):
"""A generic template view passes kwargs as context.""" """A generic template view passes kwargs as context."""
@ -603,3 +607,17 @@ class DeprecationTests(SimpleTestCase):
str(response.context['foo2']) str(response.context['foo2'])
self.assertEqual(response.context['key'], 'value') self.assertEqual(response.context['key'], 'value')
self.assertIsInstance(response.context['view'], View) self.assertIsInstance(response.context['view'], View)
@ignore_warnings(category=RemovedInDjango40Warning)
def test_template_params_filtering(self):
class ArtistView(TemplateView):
template_name = 'generic_views/about.html'
def get_context_data(self, *, artist_name, **kwargs):
context = super().get_context_data(**kwargs)
artist = Artist.objects.get(name=artist_name)
return {**context, 'artist': artist}
artist = Artist.objects.create(name='Rene Magritte')
response = ArtistView.as_view()(self.rf.get('/'), artist_name=artist.name)
self.assertEqual(response.context_data['artist'], artist)