{{{
class OfferView(TemplateView):
template_name = "offers/offer.html"
def get_context_data(self, **kwargs):
offer_slug = kwargs.get("offer_slug", "")
offer = get_object_or_404(Account, slug=offer_slug)
return {"offer": offer, "offer_slug": offer_slug}
}}}
In order to make this work in 3.1, you have to explicitly convert the
result of kwargs.get() to a string to get the SimpleLazyObject to resolve:
{{{
class OfferView(TemplateView):
template_name = "offers/offer.html"
def get_context_data(self, **kwargs):
offer_slug = kwargs.get("offer_slug", "")
offer = get_object_or_404(Account, slug=str(offer_slug))
return {"offer": offer, "offer_slug": offer_slug}
}}}
The error generated if you don't is:
**Error binding parameter 0 - probably unsupported type**
from **django/db/backends/sqlite3/operations.py**, line 144, in
_quote_params_for_last_executed_query
In both cases, the urls.py looks like:
{{{
path(
"/offers/<slug:offer_slug>/",
OfferView.as_view(),
name="offer_view",
),
}}}
When debugging, I found that offer_slug (coming in from kwargs.get) was of
type '**SimpleLazyObject**' in Django 3.1, and when I explicitly converted
it to a string, get_object_or_404 behaved as expected.
This is using Python 3.7.8 with SQLite.
--
Ticket URL: <https://code.djangoproject.com/ticket/31877>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:1>
* severity: Normal => Release blocker
* cc: Adam (Chainz) Johnson (added)
* component: Database layer (models, ORM) => Generic views
* keywords: SQLite =>
* stage: Unreviewed => Accepted
Comment:
Thanks for the report. `get_object_or_404()` and `QuerySet.filter()` with
`SimpleLazyObject` throw the same exception in Django 2.2 or 3.0.
`TemplateView.get_context_data()`'s `kwargs` returns `SimpleLazyObjects`
in Django 3.1 which causes a crash. Passing URL kwargs into context is
deprecated (see #19878) but should still work in Django 3.1 and 3.2.
Regression in 4ed534758cb6a11df9f49baddecca5a6cdda9311.
Reproduced at 60626162f76f26d32a38d18151700cb041201fb3.
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:2>
* owner: nobody => Adam (Chainz) Johnson
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:3>
Comment (by Adam (Chainz) Johnson):
Using lazy() instead of SimpleLazyObject() fixes this - PR is up.
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:4>
* has_patch: 0 => 1
Comment:
[https://github.com/django/django/pull/13297 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:5>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:6>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"20799cc0a6d98816b9ef0577e24691bd26b80d7d" 20799cc0]:
{{{
#!CommitTicketReference repository=""
revision="20799cc0a6d98816b9ef0577e24691bd26b80d7d"
Fixes #31877 -- Used lazy() for TemplateView kwarg deprecation warning.
SimpleLazyObjects cause a crash when filtering.
Thanks Tim L. White for the report.
Regression in 4ed534758cb6a11df9f49baddecca5a6cdda9311.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:7>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"9ae40d813796b70eb57bb957a19a72213e97179c" 9ae40d81]:
{{{
#!CommitTicketReference repository=""
revision="9ae40d813796b70eb57bb957a19a72213e97179c"
[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 4ed534758cb6a11df9f49baddecca5a6cdda9311.
Backport of 20799cc0a6d98816b9ef0577e24691bd26b80d7d from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:8>
* status: closed => new
* resolution: fixed =>
Comment:
Passing deprecated keyword arguments to a queryset with lookups, e.g.
`Artist.objects.get(name__iexact=artist_name)`, still crashes on
PostgreSQL:
{{{
django.db.utils.ProgrammingError: can't adapt type '__proxy__'
}}}
Thanks Mohit Solanki for the report.
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:9>
Comment (by Adam (Chainz) Johnson):
😟 Hmm this is a tough one.
psycopg2 uses `type(obj)` to look for its "adapter" - in its C extension:
https://github.com/psycopg/psycopg2/blob/e14e3385b4809ec4223894f8c7a009b1560eb41d/psycopg/microprotocols.c#L151
. So this "proxy" approach may not be feasible.
I know of a more accurate proxy wrapper that proxies more attributes than
Django's lazy objects - wrapt.ObjectProxy -
https://wrapt.readthedocs.io/en/latest/wrappers.html#object-proxy. But
docs there acknowledge that it can't even make `type()` work, whilst it
makes `isinstance()` work.
Any ideas of alternative approaches?
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:10>
* has_patch: 1 => 0
* stage: Ready for checkin => Accepted
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:11>
Comment (by Tom Forbes):
There isn't really a general purpose way of wrapping primitive/arbitrary
types like this in Python that won't hit some corner cases. You can make
an object appear to be a duck by adapting it's quacking dynamically (i.e
`wrapt.ObjectProxy`), but if someone looks close enough they can always
see that it's actually dog. And on the whole that's a good thing, IMO.
Our use of `kwargs` makes this harder as we lose the ability to construct
a container that can trigger the deprecation warning which would be the
typical easy approach. There is no way to control what lands on the other
side of `get_context_data()` (it's always a plain kwargs dict), and there
is no way to construct a wrapper value that looks _exactly_ like the value
it's wrapping.
That basically leaves only "crazy" approaches, some of which are fun to
consider but none of which are suitable. Here's one that uses `settrace()`
to do what we need:
{{{
import sys
class DeprecatedWrapper(dict):
def __getitem__(self, key):
warnings.warn("stop right there, scoundrel!")
return super().__getitem__(key)
def wrap_kwargs(frame, *args):
frame['kwargs'] = DeprecatedWrapper(frame['kwargs'])
sys.settrace(None)
class TemplateView(...):
def get(...):
...
sys.settrace(wrap_kwargs)
context = self.get_context_data(**context_kwargs)
return self.render_to_response(context)
}}}
Given these issues, I'm not sure if we can go ahead with deprecating this.
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:12>
* cc: Tom Forbes (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:13>
* has_patch: 0 => 1
Comment:
Agreed, we should revert it since we don't have a clear deprecation path.
[https://github.com/django/django/pull/13341 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:14>
Comment (by Adam (Chainz) Johnson):
I agree too.
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:15>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"bb8f66934d93faf80cd1a2dda65aaedce21a6fc5" bb8f6693]:
{{{
#!CommitTicketReference repository=""
revision="bb8f66934d93faf80cd1a2dda65aaedce21a6fc5"
Fixed #31877 -- Reverted "Fixed #19878 -- Deprecated TemplateView passing
URL kwargs into context."
This reverts commit 4ed534758cb6a11df9f49baddecca5a6cdda9311.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:17>
* status: new => closed
* resolution: => fixed
Comment:
In [changeset:"04e87e79a0bd2b1b9fdc30f884a637a3268733f0" 04e87e79]:
{{{
#!CommitTicketReference repository=""
revision="04e87e79a0bd2b1b9fdc30f884a637a3268733f0"
Refs #31877 -- Reverted "Fixes #31877 -- Used lazy() for TemplateView
kwarg deprecation warning."
This reverts commit 20799cc0a6d98816b9ef0577e24691bd26b80d7d.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:16>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"f247c66bb5f95541d16143ef37452bb1dfeacc3e" f247c66b]:
{{{
#!CommitTicketReference repository=""
revision="f247c66bb5f95541d16143ef37452bb1dfeacc3e"
[3.1.x] Refs #31877 -- Reverted "Fixes #31877 -- Used lazy() for
TemplateView kwarg deprecation warning."
This reverts commit 20799cc0a6d98816b9ef0577e24691bd26b80d7d.
Backport of 04e87e79a0bd2b1b9fdc30f884a637a3268733f0 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:18>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"e81aa7a94addf1f5380960fe89a49d104889c96d" e81aa7a]:
{{{
#!CommitTicketReference repository=""
revision="e81aa7a94addf1f5380960fe89a49d104889c96d"
[3.1.x] Fixed #31877 -- Reverted "Fixed #19878 -- Deprecated TemplateView
passing URL kwargs into context."
This reverts commit 4ed534758cb6a11df9f49baddecca5a6cdda9311.
Backport of bb8f66934d93faf80cd1a2dda65aaedce21a6fc5 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/31877#comment:19>