I'm working through the Django 1.4 tutorial, and I notice that in the view layer, URLs are assembled by hand:
<form action="/polls/{{ poll.id }}/vote/" method="post">
And so on.
However, on the controller side, URLs are generated dynamically:
return HttpResponseRedirect(reverse('polls.views.results', args=(p.id,)))
Something seems a little inconsistent about this. Since the prefix for the URL (/polls in this case) is determined in the project's URLconf instead of the application's URLconf, it seems unwise to hard-code this value in the template.
Is there a helper or some other way to generate a URL in a Django template so that it takes the URLconf into account?
Yes, you can use the builtin url-tag to avoid hardcoding a path.
For example:
{% url 'myapp:view-name' %}
Related
I am integrating django-zinnia 0.12.3 into my django 1.4 project. I have it installed and working. I want to override its zinnia/base.html template so that all the content appears using my site's template. The zinnia templates extend 'zinnia/base.html'.
When I copy the file zinnia/templates/zinnia/base.html to myproject/templates/zinnia/base.html all the zinnia {% url %} stopped working and gave NoReverseMatch. Even if I made zero changes to the file. For example:
{% url 'zinnia_entry_archive_index' %} --> returns:
NoReverseMatch Reverse for ''zinnia_entry_archive_index'' ... not found
{% url 'admin:app_list' 'zinnia' %}" title="{% trans "Dashboard" %} --> returns:
NoReverseMatch u"'admin" is not a registered namespace
I was solved the problem by removing the quotes around the url names, for example:
{% url zinnia_entry_archive_index %}
However, if I remove the copy of base.html that I put in myproject/templates/zinnia (in other words it uses the original one in the zinnia project), the urls work again.
My question is why does it work with the quotes inside the original zinnia folder, but not from within my project folder?
The reason is that in Django <= 3 the url tag takes url name without quotes. But in Django 1.4+ it is deprecated and url name without quotes is gone in Django 1.5:
So if you are using Django <= 1.4 do not remove the quotes (unless you are passing context variable) around url names. Instead do this for compatibility reason if you ever wanted to upgrade your django version:
{% load url from future %}
{% url 'zinnia_entry_archive_index' %}
Documentation
Don’t forget to put quotes around the function path or pattern name!
Changed in Django 1.5: The first parameter used not to be quoted, which was inconsistent > with other template tags. Since Django 1.5, it is evaluated according to the usual rules: > it can be a quoted string or a variable that will be looked up in the context.
In my view, I want to make a request to mine.com/more/stuff/ from an arbitrary page such as mine.com/lots/of/stuff/to/use or from mine.com. Thus, I can't make this a relative request using ./ or ./../ type things. Do I have to use a context processor to do {{URL_BASE}}more/stuff/? Is there a set way to do this in Django or a best way?
why don't you use named urls? it's always works.
for example {% url 'admin:index' %} always printed as url to admin(in case if you using default django.contrib.admin app).
if you'll have in urls.py smth like
url(r'^lots/', Lots.as_view(), name='lots'),
then just use smth like
{% url 'lots' %}
Don't hardcode your urls!
Instead of a relative url, use an absolute url: /
If you're on mine.com/lots/of/stuff/to/use or mine.com, hitting a link with url: /foo/ will both go to mine.com/foo/
Why did the django core developers allow the url templatetag to point directly to a django view function? (reference - https://docs.djangoproject.com/en/dev/ref/templates/builtins/#url)
{% load url from future %}
{# 1st method: pointing to a view function #}
{% url 'app_views.client' %}
{# 2nd method: pointing to a named url #}
{% url 'myapp:view-name' %}
One can already name the url in urls.py and hence use the 2nd method to point to a specific url. It doesn't feel right to allow developers to actually reference a view function directly from the template.
Does anyone know why this decision was made?
Passing a dotted view function name to the {% url %} template tag is simply the form the template tag took in the earlier days of Django, before you could name URLs. It's still supported, though as you point out, you probably wouldn't use it in a modern application.
URLs in Django are just mappings to views. Therefore, in the template, using a named URL is just indirectly referencing the view anyway.
The exception is where a single view is mapped to by multiple URLs.
Also note that they are planning to change the syntax of the url tag in 1.5. It will take a context variable as the parameter, rather than a string. It will still take views or named URLs though.
I am using url tag in my template for a view, that is used by two different urls. I am getting the wrong url in one place. Is there any way to force django to retrieve different url? Why it doesn't notify my, that such conflict occured and it doesn't know what to do (since python zen says, that is should refuse temptation to guess).
Code in template:
{% url djangoldap.views.FilterEntriesResponse Entry=entry.path as filter_url %}
Code in urls:
(r'^filter_entries/(?P<Entry>.*)/$',
'djangoldap.views.FilterEntriesResponse',
{'filter_template': 'filter_entries.html',
'results_template': 'filter_results.html'}),
(r'^choose_entries/(?P<Entry>.*)/$',
'djangoldap.views.FilterEntriesResponse',
{'filter_template': 'search_entries.html',
'results_template': 'search_results.html'}),
As you can see, those two urls use the same view, but with different templates. How I can force django to retrieve former url, rather than latter?
Name your URLs by adding another item to the tuple:
(r'^choose_entries/(?P<Entry>.*)/$',
'djangoldap.views.FilterEntriesResponse',
{'filter_template': 'search_entries.html',
'results_template': 'search_results.html'},
'sensibleprefix-choose_entries') # <-- this is the name
Then you can use the name in the URL tag.
In my Django project, I used to have a single URLConf, urls.py at the root of the project. This URLConf included some named URLs using Django's url() function. In several templates, I reference these URLs with the url tag, à la {% url named_url %}. This worked fine.
The root urls.py became a bit unwieldy, so I split it off into a URLConf for each app, in app/urls.py. Some URLs still have names. Unfortunately, I get a TemplateSyntaxException when using the url tag in templates now. Specifically, the error message is:
Caught an exception while rendering: Reverse for 'myproj.myapp.new_test' with arguments '()' and keyword arguments '{}' not found.
Is there a way to reference the named URLs in the app-specific URLConfs using the url tag in Django?
You definitely can reference urls in included urlconfs via the url tag - that's in fact what you're supposed to do. However, I've always found the url tag and the reverse() function to be very flaky and error-prone, so these errors do sometimes occur.
My suggestion would be to give all your urls a name, no matter which urlconf they are in. Then you just need to refer to the actual name - you don't need to qualify it with the name of the app or urlconf or anything. See if that works.
Are you referencing each app's urls.py?
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^app1/', include('app1.urls')),
(r'^app2/', include('app2.urls')),
)
from Django Docs
Probably not useful to you but hopefully useful to the next bloke searching for an answer:
I am using Django 1.4 and what solved it for me was not using quotes in the template tag:
{% url 'name_of_view' some_var %}
became this:
{% url name_of_view some_var %}
And that cured it. I didn't see any mention of this in the django docs and the examples in the docs use quotes. So this seems a little buggy but hopefully will keep someone from pulling out their hair.
https://docs.djangoproject.com/en/dev/topics/http/urls/#naming-url-patterns
I can recommend you two things:
Use name in url patterns
Do not do references to the project name inside a app(like you did with "myproj.myapp.new_test". If this was the "right way to do", you should only reference as "myapp.new_test"