Opened 2 hours ago

Last modified 65 minutes ago

#36796 new Bug

URL resolution breaks if route defined with lazy string and uses an include

Reported by: Andrea Angelini Owned by:
Component: Core (URLs) Version: 6.0
Severity: Release blocker Keywords: gettext_lazy, lazy
Cc: Andrea Angelini, Jake Howard Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

After this commit:

https://github.com/django/django/commit/f920937c8a63df6bea220e4386f59cdb45b2e355

this is not working if self._route is gettext_lazy('test'):

        elif path.startswith(self._route):
            return path.removeprefix(self._route), (), {}

More info here:
https://forum.djangoproject.com/t/gettext-lazy-and-url-patterns/43703

Change History (6)

comment:1 by Andrea Angelini, 111 minutes ago

Cc: Andrea Angelini added
Type: UncategorizedBug

comment:2 by Jacob Walls, 90 minutes ago

Cc: Jake Howard added
Keywords: gettext_lazy lazy added
Severity: NormalRelease blocker
Summary: gettext_lazy and url patternsURL resolution breaks if route defined with lazy string and uses an include
Triage Stage: UnreviewedAccepted

Thanks, replicated like this (traceback given in forum post):

from django.urls import path, include
from django.utils.translation import gettext_lazy as _

urlpatterns = [
    path(_(''), include("django.conf.urls.i18n"), name='index'),
]

It's documented that the route arg to path() can take a lazy string.

Last edited 89 minutes ago by Jacob Walls (previous) (diff)

comment:3 by Andrea Angelini, 87 minutes ago

Amended like following fixes this issue:

elif path.startswith(str(self._route)):
    return path.removeprefix(str(self._route)), (), {}

comment:4 by Jake Howard, 83 minutes ago

I'd missed that lazy string were accepted, and surprised a test didn't cover this behaviour.

Just handling the elif case won't quite work, since there's also the endpoint case. Converting self._route to a string (as part of match, rather than the constructor so it's evaluated in the correct context) sounds like the right solution. It'd be nice if the conversion only happens once per match to avoid unnecessary extra work.

comment:5 by Andrea Angelini, 73 minutes ago

I agree with you that it should be converted to a string as part of match and not as I proposed here

Last edited 72 minutes ago by Andrea Angelini (previous) (diff)

comment:6 by Andrea Angelini, 67 minutes ago

In the endpoint seems accidentally to work though because gettext_lazy('test') == 'test' returns True, while
'test'.startswith(gettext_lazy('test')) and 'test'.removeprefix(gettext_lazy('test')) throw an error

Last edited 65 minutes ago by Andrea Angelini (previous) (diff)
Note: See TracTickets for help on using tickets.
Back to Top