3

In my Django app I have these urlpatterns:

urlpatterns = [
    url(r'^$', schema_view, name='swagger'),
    url(r'^(?P<page_title>.+)/(?P<rev_id>[0-9]+)/$',
        WhoColorApiView.as_view(), name='wc_page_title_rev_id'),
    url(r'^(?P<page_title>.+)/$',
        WhoColorApiView.as_view(), name='wc_page_title'),
]

The second entry will match a path like /en/whocolor/v1.0.0-beta/my_book_title/1108730659/?origin=* and the third will match a path like /en/whocolor/v1.0.0-beta/my_book_title/?origin=*.

The idea is that it's matching a page_title parameter (a Wikipedia article title), and an optional integer rev_id (revision id) parameter.

However, it does not work as intended for an article titled "Post-9/11", with path /en/whocolor/v1.0.0-beta/Post-9%2f11/?origin=*. I want this not to match the second pattern (which gets matched as page_title "Post-9" and rev_id 11), and instead match the third pattern.

I understand why the second pattern should match if the path is /en/whocolor/v1.0.0-beta/Post-9/11/?origin=*, but when the title is url-encoded as "Post-9%2f11" it still matches the second pattern instead of continuing on to the third pattern.

How can I make Django treat the url-encoded slash as part of the parameter instead of a path separator?

Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39
Sage Ross
  • 561
  • 5
  • 12
  • 4
    To stop fighting "titles written by hands" vs "encoding/decoding urls" there is such a thing as [slug](https://docs.djangoproject.com/en/4.1/ref/models/fields/#slugfield) and [slugify](https://docs.djangoproject.com/en/4.1/ref/utils/#django.utils.text.slugify) method . Use slugs, not titles for your urls. – Ivan Starostin Sep 07 '22 at 06:42
  • Which django version are you on? – treuss Sep 16 '22 at 16:19

1 Answers1

0

In Django there's something called Path Converters.

One of the existing path converters deals with things with slashes

path - Matches any non-empty string, including the path separator, '/'. This allows you to match against a complete URL path rather than a segment of a URL path as with str.

path('<path:page_title>/',
         views.post_detail,
         name='post_detail'),

When one uses path one doesn't need to escape anything, and it'll work. There are various cases similar to OP's where Path was used as a solution, such as:


As Ivan Starostin mentions in a comment, OP should actually use the path converter slug.

According to the docs

A slug is a short label for something, containing only letters, numbers, underscores or hyphens.

For example, building-your-1st-django-site.

To do so, it's advisable that OP uses, in the model, a field of type SlugField.

slug = models.SlugField(max_length=250)

Then in the urls.py

path('<slug:post>/',
         views.post_detail,
         name='post_detail'),
Gonçalo Peres
  • 11,752
  • 3
  • 54
  • 83
  • Will this path converter approach work even when that portion of the path needs to be able to handle a url-encoded slash? In this case, the "page_title" parameter is a Wikipedia article title, and Wikipedia article titles can include a slash (as in the "Post-9/11" example). That's a constraint external to this Django app. All I want to be able to do is *not* convert `%2f` back to a slash before it hits this url pattern matcher, so that it can handle a request for a Wikipedia page that does include a slash in the page title. – Sage Ross Sep 14 '22 at 17:34
  • @SageRoss When one uses path one doesn't need to escape anything, and it'll work. See the updated answer with some examples. – Gonçalo Peres Sep 14 '22 at 22:28