How does Django map the urls when there is ambiguity - python

I have the url patterns in my project urls.py
url(r'^', include('app.urls')),
url(r'^api/app/', include('app.url.router_urls')),
and in the app.urls i have something like
url(r'^api/app/user$', views.user_validator),
and in the app.url.router_urls i have something like
url('^v1/', include('app.url.app_v1.urls'))
I have a question around these.
so when the request is BASE_URL/api/app/{user} which url will be mapped to this?
and how about BASE_URL/api/app/v1/ which url will be mapped.
this will map first with ^ right and will use the app.urls for both?
thanks

Django will fire the first view for which the URL matches. It thus evaluates the urls top-to-bottom.
It will thus first look to the included app.urls and if that matches (if you visited hostname/api/app/user, it will "fire" that view.
Note that here your user is not a variable, this is simply the word user, so if you visit {user}, it will keep looking, but since none of the patterns "fire", it will thus return a 404.
You can work with URL parameters, with:
url(r'^api/app/(?P<user>[\w{}]+)$', views.user_validator),
If we do this however, it will also match with hostname/api/app/v1, since then it sees that [\w{}]+ matches with v1.
Therefore it is important to order the url patterns from more specific to less specific, or even better: design the URL patterns such that there is no overlap.
Note: As of django-3.1, url(…) [Django-doc] is
deprecated in favor of re_path(…) [Django-doc].
Furthermore a new syntax for paths has been introduced with path converters: you
use path(…) [Django-doc] for that.

Related

Why urls order is important in django for different named urls?

I have two urls in my urls.py file
url('to_quotation/$', views.to_quotation, name='to_quotation'),
url('turn_into_quotation/$', views.turn_into_quotation, name='turn_into_quotation'),
and i have two view for them in views.py. When i make an ajax call to 'turn_into_quotation' url, 'to_quotation' view works. But if i changed my urls.py as:
url('turn_into_quotation/$', views.turn_into_quotation, name='turn_into_quotation'),
url('to_quotation/$', views.to_quotation, name='to_quotation'),
it works properly.
What is the reason for that?
You are missing the ^ at the beginning of the regex. Change it to:
url(r'^to_quotation/$', views.to_quotation, name='to_quotation'),
url(r'^turn_into_quotation/$', views.turn_into_quotation, name='turn_into_quotation'),
Without the ^, to_quotation/$ matches to_quotation/ and also turn_into_quotation/. In that case, the order matters, because Django will use the first URL pattern that matches.
If you're using a recent version of Django, you could use path() instead, and avoid regex gotchas.
path('to_quotation/', views.to_quotation, name='to_quotation'),
path('turn_into_quotation/', views.turn_into_quotation, name='turn_into_quotation'),
#Alasdair's answer is amazing~ I'd like to attach more infomations:
Django use regex-like syntax to match it and split url's argument:
^to-quotation/<id: int>/$`
It will: 1. try to match the url, 2. try to split its argument from url, and here it split int-value to id.
So it is easy to know, in the url's settings, it is important to hold each sub-url cannot match another.

Django redirect preserving subpath

In my urls.py I have:
urlpatterns = [
url(r'^admin/', admin.site.urls, name='admin'),
url(r'^django-admin/', RedirectView.as_view(url='/admin/', permanent=True)),
]
So if I go to localhost:8000/django-admin/ it successfully redirects me to localhost:8000/admin/, and if I go to localhost:8000/django-admin/my-app/ it also redirects me to localhost:8000/admin/.
How could I make localhost:8000/django-admin/my-app/ go to localhost:8000/admin/my-app/? And the same for every possible subpath e.g. localhost:8000/django-admin/my-app/my-view, localhost:8000/django-admin/another-app/, etc?
According to the docs something like this should work, you can capture groups from the path and pass them to the url
The given URL may contain dictionary-style string formatting, which will be interpolated against the parameters captured in the URL. Because keyword interpolation is always done (even if no arguments are passed in), any "%" characters in the URL must be written as "%%" so that Python will convert them to a single percent sign on output.
url(r'^django-admin/(?P<rest>.*)', RedirectView.as_view(url='/admin/%(rest)s', permanent=True)
This website is particularly useful for figuring out how the built-in class-based views work http://ccbv.co.uk/projects/Django/2.2/django.views.generic.base/RedirectView/#get_redirect_url

Django urls.py mistaking two close urls

i'm adding forms to my app to modify my lobbys (my custom model).
In urls.py, here is my urlpattern:
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^lobbys/$', views.LobbyListView.as_view(), name='lobbys'),
url(r'^lobby/(?P<pk>[\w-]+)/$', views.LobbyDetailView.as_view(), name='lobby-detail'),
url(r'^lobby/create/$', views.LobbyCreate.as_view(), name='lobby_create'),
url(r'^lobby/(?P<pk>\d+)/update/$', views.LobbyUpdate.as_view(), name='lobby_update'),
url(r'^lobby/(?P<pk>\d+)/delete/$', views.LobbyDelete.as_view(), name='lobby_delete'),
]
The problem is the following:
The third url is supposed to link to a single lobby template identifed with a UUID field as the primary key. Without the three last lines everything worked fine, but when I added my three urls for the forms, I'm getting the error
Exception Value: ["'create' is not a valid UUID."]
I understand urls.py is taking "create" as a primary key instead of considering it as an urls to an other view.
How can I bypass this problem?
Thank you very much.
You need to change the ordering of the url patterns
url(r'^lobby/create/$', views.LobbyCreate.as_view(), name='lobby_create'),
url(r'^lobby/(?P<pk>[\w-]+)/$', views.LobbyDetailView.as_view(), name='lobby-detail'),
The issue is, since lobby-detail is looking for a alphanum pattern, it also matches the pattern lobby/create. The order matters in the regex patterns, so lobby_create is never matched. By changing the order, the issue would be resolved

Django Urlconf Named Groups String Matching

I'm trying to match two strings in an url, but it's not working out likely due to my poor knowledge of regex. I want urls like the following:
testserver/username/
testserver/username/1234/
testserver/username/rewards/
Username would be passed in to the url as a kwarg. Here's what I have:
url(r'^(?P<username>[-\w]+)/$', Posts_Index, name="userposts"),
url(r'^(?P<username>[-\w]+)/photos/$', Photo_Index, name="userphotos"),
url(r'^(?P<username>[-\w]+)/rewards/$', Rewards_Index, name="userrewards"),
url(r'^(?P<username>[-\w]+)/following/$', Follower_Index, name="userfollowers"),
url(r'^(?P<username>[-\w]+)/followers/$', Following_Index, name="userfollowing"),
url(r'^(?P<username>[-\w]+)/(?P<pk>\d+)/$', SinglePost_Index, name="singlepost"),
However, only userposts will be found. If I try to query userphotos or anything below userposts, only the userposts url will be checked, which obviously leads to failure. How can I fix this issue?
From the django docs: Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL.
Thus if you reverse the order of the urls it should work better.

Best way to redirect url with extra trailing slashes in Django?

What is the best way to redirect a url like "mywebsite.com///" to "mywebsite.com/" in django?
Is there a setting that I can use in the settings.py file that is kind of the opposite of APPEND-SLASH or do I have to use
from django.views.generic.simple import redirect_to
and add a urlpattern in the urls.py file?
Edit:
I not trying to just make the webpage the same as "mywebsite.com/" i'm trying to get the actual url to change to "mywebsite.com/". Sorry for the confusion.
If you want to do this at the application level I'd avoid creating new urlconf rules, specially if it's a global thing.
You can make your own middleware to handle this redirect automatically, as django does in the common middleware for appending slashes using the APPEND_SLASH setting here is the code for reference: https://github.com/django/django/blob/master/django/middleware/common.py#L66-80
Also you may find the solution on this blog post useful: http://gregbrown.co.nz/code/append-or-remove-slash/
You should add a url pattern in the urls.py file that will match this url, with the added slashes, if you wish.
Each pattern is just a regular expression, so you can tell it to match any url with extra slashes pretty easily.
urlpatterns = patterns('django.views.generic.simple',
('^your/url/*$', 'redirect_to', {'url': '/your/url/'}),
)
By adding /* to the url pattern it will match /your/url/ with any number of slashes after it.

Categories

Resources