django template throws NoReverseMatch error - django

I had two methods create and update in the views, in which update takes one argument whereas create does not take any. I have decided to turn them into only one function update_create because they were not that different.
This is how the new method in views looks:
def update_create(request, id=None):
This is my urls.py:
url(r'^(\d+)/update/$|create/$', update_create, name='update_create'),
This is how my template looks in templates/list.html
Create a new event
I got this error when using the above code:
NoReverseMatch at /agenda/list/
Reverse for 'update_create' with arguments '()' and keyword arguments '{}' not found.
But, if I use this in my templates instead (I have added an argument), it works without any errors:
Create a new event
Can someone explain what's happening? Why previous code didn't work, and Why the new code is working?

URL pattern (\d+) expects number to be provided as argument. To resolve the issue simply provide urls like this:
url(r'^(\d+)/update/$', update_create, name='update_create'),
url(r'^update/$', update_create, name='update_create'),

As mariodev pointed out, your url pattern was expecting a digit in front of the url. As such, your first url:
Create a new event
would generate a url like /update, which wasn't a valid url. However, the latter url:
Create a new event
would generate a url like /1/update, which was a valid url.
From the django docs: https://docs.djangoproject.com/en/dev/topics/http/urls/
Basically subsequent arguments get parsed on first come first serve, and passed to your view. Another thing to consider when developing is using explicitly named parameters, as the django docs elaborate on.

Related

Django - use redirect view with multiple parameters

Im trying to redirect to a view with multiple parameters:
in my urls.py (app exhibition) I have:
path('map/<float:lat>/<float:lng>/<int:zoom>', views.MapView.as_view(), name='map')
where float is defined in a path converter like this:
'[-+]?\d*\.?\d*'
For the redirection I have:
return redirect('exhibition:map', lat=48.128365,long=11.5662713,zoom=3)
After hours of trying and researching similar questions I still get:
Reverse for 'map' with keyword arguments '{'lat': 48.128365, 'long': 11.5662713, 'zoom': 3}' not found. 1 pattern(s) tried: ['de/map\\/(?P<lat>[-+]?\\d*\\.?\\d*)\\/(?P<lng>[-+]?\\d*\\.?\\d*)\\/(?P<zoom>[0-9]+)$']
If I adjust the url pattern and the redirect call to a single pattern (be it float or int) the redirection works. Thus the problem should be related to my usage of multiple parameters - but I just can see what is wrong.
Any hints welcome!
i guess it's typo, you have defined lng as second parameter in your path but in redirect statement you call it long, it should be
return redirect('exhibition:map', lat=48.128365, lng=11.5662713, zoom=3)

What is best practice for passing variables via GET?

I am passing a variable in my URL:
mydomain.com/app/?next_page=my_page
I can get this variable in a view with:
def mypage(request):
var = request.GET['next_page']
Is it best practice to also change the URL to require next_page? Something along the lines of:
path('app/?nextpage=<str>', mypage, name='my_page')
What's best practice? If so, what's the correct syntax for this (I know the example is incorrect)?
It depends on your needs.
Do not define a fixed url route; if you use the query parameters for filtering and there is more than one possible parameter
Example: "app/photos?size=100x100" and "app/photos/?color=blue"
Define a fixed url route; if it will be the same for each and every page, like details of a particular page:
Example: "app/orders/123123123" and "app/orders/123123123"
Btw, the correct syntax is:
path(app/<str:next_page>/, mypage, name="my_page")
You should take a look at path patterns. Enforcing a GET parameter in a path is not really a good practice. So if you want to require a username for example you can use:
path('bio/<username>/', views.bio, name='bio'),
You can find more patterns in Django documentation to catch strings, slugs, integers etc.
And in views you should define your function as such:
def mypage(request, username):
...code...
About GET:
Keep in mind that request.GET["value"] will raise a ValueError if that parameter does not exist. So you can catch that error to inform user that they are missing a parameter. (This will make this parameter obligatory.)
You can also use request.GET.get("value") which will return None if the key does not exist. If you want to use a default parameter you can use of course, request.GET.get("value", "default")
You can use as many parameters as you want in your link with or without path patterns. Their values will be stored in request.GET

How to use variable at start of django url to return to view?

I am trying to pass the first part of a django url to a view, so I can filter my results by the term in the url.
Looking at the documentation, it seems quite straightforward.
However, I have the following urls.py
url('<colcat>/collection/(?P<name>[\w\-]+)$', views.collection_detail, name='collection_detail'),
url('<colcat>/', views.collection_view, name='collection_view'),
In this case, I want to be able to go to /living and have living be passed to my view so that I can use it to filter by.
When trying this however, no matter what url I put it isn't being matched, and I get an error saying the address I put in could not be matched to any urls.
What am I missing?
<colcat> is not a valid regex. You need to use the same format as you have for name.
url('(?P<colcat>[\w\-]+)/collection/(?P<name>[\w\-]+)$', views.collection_detail, name='collection_detail'),
url('(?P<colcat>[\w\-]+)/$', views.collection_view, name='collection_view'),
Alternatively, use the new path form which will be much simpler:
path('<str:colcat>/collection/<str:name>', views.collection_detail, name='collection_detail'),
path('<str:colcat>/', views.collection_view, name='collection_view'),

Django: Multiple parameters in URLs reverse resolution without querystrings or captured parameters

Without using query strings (like ?case=/2/), nor captured parameters in the url conf (like ?P) (so they dont show up in the url),
is there a way to pass parameters to a view function when using URLs reverse resolution?
Hopefully an example will clarify my question:
With captured parameters I could do:
views.py
...
return HttpResponseRedirect(reverse('videos:show_details', args=[video.id]))
urls.py
...
url(r'^club/(?P\d+)/$',views.details, name='show_details'),
...
But what if the view details needs / accepts more parameters, for example:
def details (request, video_id, director='', show_all=True):
And we dont want them to show up in the url?
Any way of using args or kwargs without them being in the url?
Im sure Im missing something trivial here :S
Hopefully someone can point me in the right direction.
Thanks!
I'm not sure this is what you mean, but you can pass extra arguments to the url pattern. This allows multiple urls that point to the same view to use different arguments:
url(r'^club/(?P<pk>\d+)/$', views.details, kwargs={'show_all': False}, name='show_details')

Django url patterns having reverse lookup issues with optional parameters

I am having some weird issues with reverse lookups. Here is my url scheme.
url(r'^overview/', 'ledger.views.overview', name='overview'),
url(r'^overview/(?P<tutorial>\w+)$', 'ledger.views.overview', name='overview_tutorial'),
When I call return redirect('overview_tutorial', tutorial='tutorial') it isn't loading the tutorial version, it is loading the regular version, which is weird to me. I thought by specifying the name of the url it would use that url but instead it is matching on the first url. Adding a $ to the end of the url scheme solves the problem:
url(r'^overview/$', 'ledger.views.overview', name='overview'),
url(r'^overview/(?P<tutorial>\w+)$', 'ledger.views.overview', name='overview_tutorial'),
but I still don't understand why it is doing this. What I really want to do is have a url scheme like this:
url(r'^overview/', 'ledger.views.overview', name='overview'),
url(r'^overview/(?P<tutorial>\w+)$', 'ledger.views.overview', name='overview_tutorial'),
url(r'^overview/(?P<success>\w+)$', 'ledger.views.overview', name='overview_success'),
url(r'^overview/(?P<error>\w+)$', 'ledger.views.overview', name='overview_error')
and then I can redirect to the appropriate appropriate url name and pass in the different parameters. ie:
return redirect('overview_success', success='True') #or
return redirect('overview_error', error='Login failed. Please try your username/password again')
but those both return as if I just called tutorial view. (which I am now realizing is because a reverse url lookup must build the url and then run it through the url patterns to see where it should direct to).
So then I tried doing this:
url(r'^overview/(?P<tutorial>\w+)$', 'ledger.views.overview', name='overview'),
url(r'^overview/(?P<tutorial>\w+)/(?P<success>\w+)$', 'ledger.views.overview', name='overview_success'),
url(r'^overview/(?P<tutorial>\w+)/(?P<success>\w+)/(?P<error>\w+)$', 'ledger.views.overview', name='overview_error'),
but when I call return redirect("overview_success", tutorial='', success="Hooray"), I again get an error:
Reverse for 'overview_success' with arguments '()' and keyword arguments '{'success': 'Hooray', 'tutorial': ''}' not found. 1 pattern(s) tried: ['overview/(?P<tutorial>\\w+)/(?P<success>\\w+)$']
It looks like you are trying to use your urlconf to accept messages that you want to send to the user. For example your error message
return redirect('overview_error', error='Login failed. Please try your username/password again')
However that's not what named groups in the urlconf are for. They are for matching url patterns to determine which view to render. So when you are calling redirect it isn't just sending you to a new url, it's resolving that url based on what you pass it.
In your second example your redirect call
return redirect("overview_success", tutorial='', success="Hooray")
is trying to match against your url pattern
url(r'^overview/(?P<tutorial>\w+)/(?P<success>\w+)$', 'ledger.views.overview', name='overview_success'),
as something like overview//Hooray which as you can see is not a valid pattern because of the empty string passed to tutorial which expects 1 or more "word" characters.
You can use the messaging framework to send messages to the user. https://docs.djangoproject.com/en/1.7/ref/contrib/messages/#module-django.contrib.messages