5

in one of our Django applications we have defined multiple urls for views.

The first URL matches a general feature with pk and a second match group. The second URL matches a subfeature with pk.

Between this two urls more urls are defined, so it is not easy to see them all at once. Or, for example, the subfeature would have its own url.py.

# old urls.py
url(r'^(?P<pk>\d+)/', views.b),
url(r'^subfeature/', views.a),

After some time letters are also allowed in pk, so we now have to change \d+ to [^/]+.

# new urls.py
url(r'^(?P<pk>[^/]+)/', views.b),
url(r'^subfeature/', views.a),

Now the subfeature breaks because the url is not correctly matched, 'subfeature' is matched as pk in the first url.

How to avoid breaking other urls when changing a url regex?

1
  • What if you change the order of the regexes? Commented Oct 13, 2016 at 14:27

4 Answers 4

9
+50

There's no general answer to that. Any change that makes an url more generic may break other urls that follow it.

In this case, you can swap the urls so subfeature/ will match the subfeature url, and any other url will fall through and match views.b:

url(r'^subfeature/', views.a),
url(r'^(?P<pk>[^/]+)/', views.b),
Sign up to request clarification or add additional context in comments.

Comments

6

My advice would be that you should apply similar naming principles as a RESTful interface and so never expose the raw PK alone as a URL.

Instead, you should always provide some sort of namespace to make it clear what your URL is referencing. For example:

# new urls.py
url(r'^feature/(?P<pk>[^/]+)/', views.b),
url(r'^subfeature/', views.a),

Not only does this solve your problem, but it also prevents potential confusion between multiple table PKs and makes it much easier to extend in the future. Incidentally, it is also in line with the django docs.

This should be an easy change as long as you have control over the GUI too. However, if your existing URL must be retained, the other answers are more appropriate.

Comments

1

As a general rule, you need to take the order into consideration when defining urlpatterns.

The thing is django will try to find the match by trying to fit a url into every pattern and will try to get to the views whenever it finds the first url matching.

url(r'^(?P<pk>[^/]+)/', views.b),
url(r'^subfeature/', views.a),

Here, it will first match the url with the first pattern where there is a variable initially and will try to put "subfeature" as pk and will tell you that it could not find any object with id="subfeature" (one pattern tried)

So yes, go with solution of user knbk. reverse the order and keep this in mind.

Comments

0

Django's URL are matched in the order they are defined in the urls.py file. The issue you are facing is because your regex pattern matches the subfeature as the part of url and calls the in-correct view.

Instead of complicating the logic of regex, I 'll suggest you to make it simpler, as regex matching is heavy computation task especially when you are dealing with APIs with rate of millions of request per second.

Just change the order in which you defined the URLs. For example, order should be like:

 /my-object/
 /my-object/category/
 /my-object/category/(?P<pk>[^/]+)/
 /my-object/(?P<pk>[^/]+)/

Hence, in your case order of URL declaration should be reversed as:

url(r'^subfeature/', views.a),
url(r'^(?P<pk>[^/]+)/', views.b),

Now, firstly "subfeature" will be matched as the whole text. In case of mismatch, request will go to the next URL which is your regex pattern.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.