Используя {% url ??? %} в шаблонах django

84

Я много искал в Google ответы о том, как использовать тег «url» в шаблонах, только чтобы найти много ответов, в которых говорилось: «Просто вставьте его в свой шаблон и укажите на то представление, для которого требуется URL-адрес». Что ж, никакой радости для меня :( Я пробовал все возможные варианты и прибегал к публикации здесь в крайнем случае.

Итак, вот оно. Мой urls.py выглядит так:

from django.conf.urls.defaults import *
from login.views import *
from mainapp.views import *
import settings

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Example:
    # (r'^weclaim/', include('weclaim.foo.urls')),
    (r'^login/', login_view),
    (r'^logout/', logout_view),
    ('^$', main_view),

    # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 
    # to INSTALLED_APPS to enable admin documentation:
    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    (r'^admin/', include(admin.site.urls)),
    #(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': '/home/arthur/Software/django/weclaim/templates/static'}),
    (r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.MEDIA_ROOT}),
)

Мой 'views.py' в моем каталоге 'login' выглядит так:

from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.contrib import auth

def login_view(request):
    if request.method == 'POST':
        uname = request.POST.get('username', '')
        psword = request.POST.get('password', '')
        user = auth.authenticate(username=uname, password=psword)
        # if the user logs in and is active
        if user is not None and user.is_active:
            auth.login(request, user)
            return render_to_response('main/main.html', {}, context_instance=RequestContext(request))
            #return redirect(main_view)
        else:
            return render_to_response('loginpage.html', {'box_width': '402', 'login_failed': '1',}, context_instance=RequestContext(request))
    else:
        return render_to_response('loginpage.html', {'box_width': '400',}, context_instance=RequestContext(request))

def logout_view(request):
    auth.logout(request)
    return render_to_response('loginpage.html', {'box_width': '402', 'logged_out': '1',}, context_instance=RequestContext(request))

и, наконец, main.html, на который указывает login_view:

<html>
<body>
test! <a href="{% url logout_view %}">logout</a>
</body>
</html>

Так почему я каждый раз получаю «NoReverseMatch»?

* (немного другое примечание, мне пришлось использовать context_instance = RequestContext (request) в конце всех моих запросов на рендеринг в ответ, потому что в противном случае он не распознал бы {{MEDIA_URL}} в моих шаблонах, и я не мог ссылаться любые файлы css или js. Я не уверен, почему это так. Мне это не кажется правильным) *

Роберт Джонстон
источник
1
То, что вы говорите о context_instance=RequestContext(request)шаблоне, правильно, это необходимо, чтобы разрешить шаблону доступ к переменным контекста, предоставленным всем шаблонам. Это делается по умолчанию для всех общих представлений, но вам нужно сделать это самостоятельно в своих пользовательских.
Маркус Уайброу
Мне это кажется немного странным, потому что вы будете постоянно получать доступ к своим css и js файлам из своих шаблонов, чтобы поддерживать согласованность на своем сайте. Поэтому разве вы не должны иметь доступ к {{MEDIA_URL}} по умолчанию?
Роберт Джонстон
1
Принятый ответ здесь больше недействителен
Дэн Гейл
Добавьте новый ответ, и тогда я приму его
Роберт Джонстон

Ответы:

55

Вместо импорта logout_viewфункции вы должны указать строку в своем urls.pyфайле:

Так что не (r'^login/', login_view),

но (r'^login/', 'login.views.login_view'),

Это стандартный способ работы. Затем вы можете получить доступ к URL-адресу в своих шаблонах, используя:

{% url login.views.login_view %}
Маркус Уайброу
источник
2
да, определенно используйте струны. таким образом, вы также можете использовать префиксы, и вам не нужно импортировать все свои функции просмотра в свой URLConf.
Шри Рагхаван
Я тоже пробовал это и получил «Пойман NoReverseMatch при рендеринге: обратный для« login.views.login_views »с аргументами« () »и аргументами ключевого слова« {} »не найден». снова :(
Роберт Джонстон
Подождите ... Поцарапайте это! Я ждал 15 минут, попробовал еще раз, и это сработало (ура !!!). Приятно 1. Следующий вопрос. Если у меня есть только один сайт, который я добавил на страницу администратора, как я могу добавить суффикс к {% url ??? %}
Роберт Джонстон
Да, это некро, но тег URL все еще кусает меня в 2015 году. Было бы неплохо, если бы они не продолжали менять синтаксис:
Дэйв,
6
Просто потому, что я пришел сюда из Google, я должен сказать, что что касается django 1.8+, передача строк в качестве аргумента представления устарела и скоро будет удалена. Фактически вы должны передать вызываемый объект, как в этом посте.
user3599803
104

Выбранный ответ устарел, и у меня не работали другие (Django 1.6 и [очевидно] без зарегистрированного пространства имен.)

Для Django 1.5 и новее (из документации )

Предупреждение Не забудьте заключить в кавычки путь к функции или имя шаблона!

С именованным URL-адресом вы можете:

(r'^login/', login_view, name='login'),
...
<a href="{% url 'login' %}">logout</a>

Так же просто, если представление принимает другой параметр

def login(request, extra_param):
...
<a href="{% url 'login' 'some_string_containing_relevant_data' %}">login</a>
Майк С
источник
1
Да, я знаю. Сейчас использую {% load url from future %}1.4. Хорошее место
Роберт Джонстон
5
Это следует выбрать в качестве ответа. Использование строк для обратного сопоставления URL-адресов не рекомендуется в новых версиях django.
Sumudu
44

Убедитесь (django 1.5 и выше), что вы поместили имя URL-адреса в кавычки, и если ваш URL-адрес принимает параметры, они должны быть вне кавычек (я потратил часы, выясняя эту ошибку!).

{% url 'namespace:view_name' arg1=value1 arg2=value2 as the_url %}
<a href="{{ the_url }}"> link_name </a>
Богатырь
источник
Я знаю, что это старый ответ, но он мне действительно помог. Я использую django-norel, который является форком Django 1.6, который также должен иметь эту проблему, потому что инкапсуляция имени URL-адреса в кавычки устранила ошибку TypeError, которую я получал.
robobrobro
2
Использование правильной документации тоже помогает, так как они продолжают изменять синтаксис: {% url app_views.client client.id %}(без кавычек) в 1.4, {% url 'app_views.client' client.id %}(с кавычками) в 1.5 -1.7 и {% url 'app-views-client' client.id %}(без подчеркиваний или точек, только тире) в 1.8.
Дэйв
О Господи, и я планировал в ближайшее время перейти на 1.8.
Богатырь
17

urlШаблонный тег будет передать параметр в виде строки , а не в качестве функции ссылки reverse(). Самый простой способ заставить это работать - добавить nameв представление:

url(r'^/logout/' , logout_view, name='logout_view')
Бернхард Валлант
источник
Я пробовал это, но получил «неверный синтаксис (urls.py, строка 14)» :(
Роберт Джонстон
что действительно странно в этом, так это то, что оно (PyCharm - хорошее приложение) не позволяет мне использовать> name = 'logout_view' <, как указано выше, без рекомендации импорта библиотеки (libxml2mod.name или unicodedata.name или twisted.trial.runner. name)
Роберт Джонстон
Где reverse()определяется функция ?
CodyBugstein 01
В вашем шаблоне с использованием {% url 'logout_view'%} django.readthedocs.org/en/latest/intro/tutorial03.html
Хуан Рохас
12

У меня такая же проблема.

Что я нашел из документации, мы должны использовать пространство имен.

в твоем случае {% url login:login_view %}

Список
источник
В наши дни использование пространств имен стало намного больше. Делает URL-адреса более читаемыми, и они на самом деле что-то для вас значат
Роберт Джонстон
Не могли бы вы включить ссылку на документацию?
geoidesic
1

Судя по вашему примеру, разве это не {% url myproject.login.views.login_view %}конец истории? (замените myprojectфактическим названием проекта)

Юдзи Томита Томита
источник
То же, что и выше «Поймано NoReverseMatch при рендеринге: обратное для weclaim.login.views.login_views» с аргументами «()» и аргументами ключевого слова «{}» не найдено ». (Я предполагаю, что имя моего проекта совпадает с именем корневого каталога, в котором хранится весь мой код)
Роберт Джонстон,