Django urls.py mistaking two close urls - python

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

Related

How does Django map the urls when there is ambiguity

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.

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

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.

What is the difference between url() and tuple for urlpatterns in Django?

So in Django the two lines of url code below work the same:
urlpatterns = patterns('',
url(r'^login/$', 'django.contrib.auth.views.login'),
(r'^login/$', 'django.contrib.auth.views.login')
)
AFAIK, the only difference is I can define name='login' so I can use it for reversing url. But besides this, is there any other differences?
There is no difference whatsoever. Have a look at the patterns function in django.conf.urls.__init__.py, if your url is a list or tuple then it is wrapped up by the url function anyway before being appended to the list of available patterns.

Django Url Not Resolving with Query Parameters

I have an issue where I need to pass in query parameters for a GET request, but Django is not resolving the URL correctly to the view.
My urls.py looks like this:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'^confirm_cancel',
'myapp.views.confirm_cancel_method',
name='myapp_confirm_cancel'),
)
When I goto /confirm_cancel?some_id=x I get a 404, telling me "No MyModel matches query." When I set a breakpoint in my view handler, it does not get hit when I goto that url.
However, if I goto /confirm_cancel/x/, my view breakpoint does get hit.
One more thing to note, this worked in Django 1.1, but is now broken since I upgraded to 1.2.
Any thoughts?
Thanks!
I don't think the problem is with your url. Are you using a shortcut like get_object_or_4o4 somewhere in your view? For example:
get_object_or_404(MyModel, pk=99)
would result in a "No MyModel matches given query, if there wasn't a record in your table with a primary key of 99.
We need to see what's in the corresponding view function.
Ideally, it should look something like this:
def confirm_cancel_method(request, some_id=None):
some_id = request.REQUEST.get('some_id', some_id)
some_record = get_object_or_404(SomeModel, pk=some_id)
...
update
Sorry, just saw your note about the breakpoint. One thing I'd recommend is changing the config to this:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'^confirm_cancel/?$',
'myapp.views.confirm_cancel_method',
name='myapp_confirm_cancel'),
)
Adding /?$ at the end means that only /confirm_cancel or /confirm_cancel/ will match the url. Right now because you don't have the ending $ anything starting with confirm_cancel will match. Fixing the pattern will at least resolve this issue.
I had copied out all the other url patterns in the urls.py in my post.
Turns out that the issue was that I had a r'^(?P<my_id>\w+)/?$' for one of the urls at the top of the urlpatterns.
Next time I'll learn to paste everything instead of cherry picking what I think are the offending lines of code.
Strange that this did not cause Django 1.1 to break... I guess it was a bug that was fixed in 1.2
Did you check if this was a case of the trailing slash?

Categories

Resources