Opened 3 weeks ago

Closed 3 weeks ago

Last modified 3 weeks ago

#37268 closed Bug (duplicate)

django 6.1 breaks Media objects with reverse_lazy entries

Reported by: alex Owned by:
Component: Forms Version: 6.1
Severity: Normal Keywords:
Cc: Johannes Maron Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Problem

sometimes you want to use reverse_lazy for referencing internal urls in forms, widgets and other Media objects.

With the new change to Script, Stylesheet, ... this fails. Both classes cannot lazy load and when a lazy object is defined it is tried to access .__html__() which fails.

What should happen instead is to resolve reverse_lazy when it is really required. Both classes should support lazy objects too.

Why reverse won't work in such situations:

This won't work in admin. Calling reverse too early; e.g. when defining the media object can break the application.

Change History (7)

comment:1 by David Smith, 3 weeks ago

Resolution: duplicate
Status: newclosed

Thanks for the report. This seems to be a duplicate of #37262

Does the patch at https://github.com/django/django/pull/21752 work for you. Your feedback there would be welcomed.

comment:2 by Jacob Walls, 3 weeks ago

Cc: Johannes Maron added
Resolution: duplicate
Severity: NormalRelease blocker
Status: closednew
Triage Stage: UnreviewedAccepted
Type: UncategorizedBug

Django 6.0.8:

>>> from django.forms import Media
>>> from django.urls import reverse_lazy
>>> media = Media(js=reverse_lazy("reports"))

With the PR for #37262, thus not a duplicate:

>>> media = Media(js=reverse_lazy("reports"))
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/jwalls/django/django/forms/widgets.py", line 151, in __init__
    self._js_lists = [self._normalize_js(js)]
                      ~~~~~~~~~~~~~~~~~~^^^^
  File "/Users/jwalls/django/django/forms/widgets.py", line 163, in _normalize_js
    for path in js
                ^^
  File "/Users/jwalls/django/django/utils/functional.py", line 187, in __wrapper__
    result = func(*self._args, **self._kw)
  File "/Users/jwalls/django/django/urls/base.py", line 98, in reverse
    resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
  File "/Users/jwalls/django/django/urls/resolvers.py", line 842, in _reverse_with_prefix
    raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'reports' not found. 'reports' is not a valid view function or pattern name.

We document using reverse_lazy for the Stylesheet(MediaAsset) class:

    class FeedWithStylesheetView(Feed):
        stylesheets = [
            reverse_lazy("your-custom-view-name"),
        ]

So using it in Media(js=...) seems reasonable. Thanks for the report.

This probably makes rendering CSP nonces more difficult, so I'm cc'ing other knowledgable folks who might speak to implementation strategy or what caveats we might need to document.

comment:3 by Johannes Maron, 3 weeks ago

Resolution: needsnewfeatureprocess
Severity: Release blockerNormal
Status: newclosed
Triage Stage: AcceptedUnreviewed
Type: BugNew feature

Thanks for alerting me to this issue.

I don't think it's strictly a duplicate, and even with Adams patch, the hasattr check will resolve lazy objects.

If we want to address this we will need to only normalize objects during rendering and will also need to defer the media object merging.

Considering that we never really supported this, and there are not tests for this, I would consider this a feature request, not a bug.

comment:4 by Johannes Maron, 3 weeks ago

Looks like both were commented on at the same time. I would still consider this a new feature, not a bug. But you are the expert; however, adding support will be very painful.

comment:5 by Johannes Maron, 3 weeks ago

Cc: Johannes Maron removed

in reply to:  4 comment:6 by Jacob Walls, 3 weeks ago

Resolution: needsnewfeatureprocessduplicate
Type: New featureBug

Replying to Johannes Maron:

Looks like both were commented on at the same time. I would still consider this a new feature, not a bug. But you are the expert; however, adding support will be very painful.

I think the expert is you, not me :-)

Replying to Jacob Walls:

We document using reverse_lazy for the Stylesheet(MediaAsset) class:

I got mixed up... the Feed.stylesheet is not implemented using Media. Maybe similar use case in spirit at best.

Replying to Johannes Maron:

even with Adams patch, the hasattr check will resolve lazy objects.

Luckily for us, that's not what I see:

>>> from django.urls import reverse_lazy
>>> js = reverse_lazy("my.js")
>>> hasattr(js, "__html__")
False
>>> str(js)  # failure from URLs not being available
Traceback (most recent call last):

So, this may be a dupe of #37262, if it so happens that Script objects can accept reverse_lazy() objects just fine. Alex only said the __html__ call was the problem.

Alex, may I ask you to check the PR linked in comment:1? Thanks!

comment:7 by Johannes Maron, 3 weeks ago

Cc: Johannes Maron added
Note: See TracTickets for help on using tickets.
Back to Top