[3.1.x] 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.

Backport of 20799cc0a6 from master
This commit is contained in:
Adam Johnson 2020-08-12 12:19:46 +01:00 committed by Mariusz Felisiak
parent f139372491
commit 9ae40d8137
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.utils.decorators import classonlymethod
from django.utils.deprecation import RemovedInDjango40Warning
from django.utils.functional import SimpleLazyObject
from django.utils.functional import lazy
logger = logging.getLogger('django.request')
@ -169,7 +169,6 @@ def _wrap_url_kwargs_with_deprecation_warning(url_kwargs):
context_kwargs = {}
for key, value in url_kwargs.items():
# Bind into function closure.
@SimpleLazyObject
def access_value(key=key, value=value):
warnings.warn(
'TemplateView passing URL kwargs to the context is '
@ -178,7 +177,7 @@ def _wrap_url_kwargs_with_deprecation_warning(url_kwargs):
RemovedInDjango40Warning, stacklevel=2,
)
return value
context_kwargs[key] = access_value
context_kwargs[key] = lazy(access_value, type(value))()
return context_kwargs

View File

@ -25,3 +25,7 @@ Bugfixes
:meth:`~django.db.models.query.QuerySet.select_for_update()`. When using
related fields pointing to a proxy model in the ``of`` argument, the
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.http import HttpResponse
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.urls import resolve
@ -11,6 +12,7 @@ from django.utils.deprecation import RemovedInDjango40Warning
from django.views.generic import RedirectView, TemplateView, View
from . import views
from .models import Artist
class SimpleView(View):
@ -571,7 +573,9 @@ class SingleObjectTemplateResponseMixinTest(SimpleTestCase):
@override_settings(ROOT_URLCONF='generic_views.urls')
class DeprecationTests(SimpleTestCase):
class DeprecationTests(TestCase):
rf = RequestFactory()
@ignore_warnings(category=RemovedInDjango40Warning)
def test_template_params(self):
"""A generic template view passes kwargs as context."""
@ -603,3 +607,17 @@ class DeprecationTests(SimpleTestCase):
str(response.context['foo2'])
self.assertEqual(response.context['key'], 'value')
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)