0

I want my users to access a specific location of my API using either the English word "series" or the French equivalent "séries" as an argument in the URL. The URL and subsequent extensions will be reversed to using the English word. Here is my first attempt:

urlpatterns = [
    path(r"series/", include("series.public_urls", namespace="series")),
    path(r"séries/", include("series.public_urls")),
]

Despite the following warning, I have been able to reverse all my URLs so far:

?: (urls.W005) URL namespace 'series' isn't unique. You may not be able to reverse all URLs in this namespace

However a warning is a foreboding of impending doom and I'm looking for another solution. I've tried using Regex paths:

urlpatterns = [
    re_path(r"s(e|é)ries/", include("series.public_urls", namespace="series")),
]

This throws an ImproperlyConfigured error. I understand the reverser cannot handle the "or" matching control but needs to know which of e or é it should reverse to.

How can I allow reversing to "series" solely within this very urls.py file?

  • Just make a redirect in the `séries/`. So you construct a `séries//`, and you redirect to the corresponding URL with `series/`. – Willem Van Onsem Mar 02 '21 at 12:06
  • Ok do you mean `django.shortcuts.redirect`? Using redirect in my urls.py throws another variant of the `ImproperlyConfigured` error: `path(r"séries/", redirect(r"series/")),` (path) or `path(r"series/", redirect("series")),` (namespace) or even something that isn't valid in the first place: `path(r"foo/", redirect(r"bar")),` will throw: `django.core.exceptions.ImproperlyConfigured: The included URLconf 'app.urls' does not appear to have any patterns in it. If you see valid patterns in the file then the issue is probably caused by a circular import.` – Paulo Modulo Mar 02 '21 at 13:30

1 Answers1

0

First, don't try to use django.urls.reverse or django.shortcuts.redirect in any urls.py, you'll get ImproperlyConfigured because of circular logic.

A solution is to make use of django.views.generic.base.RedirectView and feed it the desired target:

urlpatterns = [
    path(r"series/", include("series.public_urls", namespace="series")),
    path(r"séries/", RedirectView.as_view(url="/series/", permanent=False)),
]

Note that in my case a slash should precede the target url, this allows domain/séries/ to redirect correctly to domain/series/. Had I not added it, domain/séries/ would redirect to domain/séries/series/.

More info in Django's documentation and in this SO topic, see another working solution actually using reverse in a lambda function down in the answers.

Important side-topic: Don't mess up the permanent argument. permanent=False will send a HTTP 302 Found response in order to inform the browser of the redirection. That's the default in Django => 1.9. If you're in development, you want that. permanent=True will send a HTTP 301 Moved Permanently response. Your browser will then always use the url it was redirected to in the future. From the server side, there is no way to modify that behaviour (that's the point of "permanent"). If you've messed up the redirection (as I did) and it has been acknowledged as permanent, you'll have to clear the browser cache or at least recent activity.