Как создать Django reverse/url с использованием запросов args?
У меня есть URL-адреса, такие как http://example.com/depict?smiles=CO&width=200&height=200 (и с несколькими другими необязательными аргументами)
My urls.py содержит:
urlpatterns = patterns('',
(r'^$', 'cansmi.index'),
(r'^cansmi$', 'cansmi.cansmi'),
url(r'^depict$', cyclops.django.depict, name="cyclops-depict"),
Я могу перейти к этому URL-адресу и получить созданный PNG 200x200, поэтому я знаю, что эта часть работает.
В моем шаблоне из ответа "cansmi.cansmi" я хочу создать URL-адрес для именованного шаблона "cyclops-pictict" с учетом некоторых параметров запроса. Я думал, что смогу сделать
{% url cyclops-pictict smiles = input_smiles width = 200 height = 200%}
где "input_smiles" - это вход в шаблон посредством представления формы. В этом случае это строка "CO", и я думал, что создаст URL-адрес, похожий на тот, который находится наверху.
Этот шаблон не работает с TemplateSyntaxError:
Показ исключений при рендеринге: Реверс для 'cyclops-pictict' с аргументами '()' и аргументами ключевого слова '{' smiles ': u'CO', 'height': 200, 'width': 200} 'not найдено.
Это довольно распространенное сообщение об ошибке как здесь, так и в StackOverflow и в других местах. В каждом случае, я обнаружил, что люди использовали их с параметрами в URL-адресе регулярного выражения URL-адреса, что не соответствует мне, где параметры входят в запрос.
Это означает, что я делаю это неправильно. Как мне это сделать правильно? То есть, я хочу построить полный URL, включая параметры пути и запроса, используя что-то в шаблоне.
Для справки,
% python manage.py shell
Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.core.urlresolvers import reverse
>>> reverse("cyclops-depict", kwargs=dict())
'/depict'
>>> reverse("cyclops-depict", kwargs=dict(smiles="CO"))
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Library/Python/2.6/site-packages/django/core/urlresolvers.py", line 356, in reverse
*args, **kwargs)))
File "/Library/Python/2.6/site-packages/django/core/urlresolvers.py", line 302, in reverse
"arguments '%s' not found." % (lookup_view_s, args, kwargs))
NoReverseMatch: Reverse for 'cyclops-depict' with arguments '()' and keyword arguments '{'smiles': 'CO'}' not found.
Ответы
Ответ 1
В вашем обычном expresion нет владельцев мест (почему вы получаете NoReverseMatch):
url(r'^depict$', cyclops.django.depict, name="cyclops-depict"),
Вы можете сделать это следующим образом:
{% url cyclops-depict %}?smiles=CO&width=200&height=200
Поиск URLconf не включает параметры GET или POST
Или, если вы хотите использовать тэг {% url%}, вы должны изменить структуру своего URL-кода на что-то вроде
r'^depict/(?P<width>\d+)/(?P<height>\d+)/(?P<smiles>\w+)$'
тогда вы можете сделать что-то вроде
{% url cyclops-depict 200 200 "CO" %}
Последующий:
Простой пример для настраиваемого тега:
from django.core.urlresolvers import reverse
from django import template
register = template.Library()
@register.tag(name="myurl")
def myurl(parser, token):
tokens = token.split_contents()
return MyUrlNode(tokens[1:])
class MyUrlNode(template.Node):
def __init__(self, tokens):
self.tokens = tokens
def render(self, context):
url = reverse('cyclops-depict')
qs = '&'.join([t for t in self.tokens])
return '?'.join((url,qs))
Вы можете использовать этот тег в своих шаблонах так:
{% myurl width=200 height=200 name=SomeName %}
и, надеюсь, он должен вывести что-то вроде
/depict?width=200&height=200&name=SomeName
Ответ 2
Создание URL-адреса со строкой запроса путем конкатенации строк, как предлагается в некоторых ответах, является такой же плохой идеей, как создание запросов SQL путем конкатенации строк. Это сложно, нелегко и особенно опасно при вводе пользователем (ненадежном) ввода. К сожалению, Django не предоставляет простой возможности передавать параметры запроса в обратную функцию.
Однако стандарт Python urllib обеспечивает желаемую функциональность кодирования строки запроса.
В моем приложении я создал вспомогательную функцию:
def url_with_querystring(path, **kwargs):
return path + '?' + urllib.urlencode(kwargs) # for Python 3, use urllib.parse.urlencode instead
Затем я называю это следующим образом:
quick_add_order_url = url_with_querystring(reverse(order_add),
responsible=employee.id, scheduled_for=datetime.date.today(),
subject='hello world!')
# http://localhost/myapp/order/add/?responsible=5&
# scheduled_for=2011-03-17&subject=hello+world%21
Обратите внимание на правильную кодировку специальных символов, таких как пробел и восклицательный знак!
Ответ 3
Я рекомендую использовать встроенный django QueryDict. Он также правильно обрабатывает списки. End автоматически ускользает от некоторых специальных символов (например, =
, ?
, /
, '#'):
from django.http import QueryDict
from django.core.urlresolvers import reverse
q = QueryDict('', mutable=True)
q['some_key'] = 'some_value'
q.setlist('some_list', [1,2,3])
'%s?%s' % (reverse('some_view_name'), q.urlencode())
# '/some_url/?some_list=1&some_list=2&some_list=3&some_key=some_value'
q.appendlist('some_list', 4)
q['value_with_special_chars'] = 'hello=w#rld?'
'%s?%s' % (reverse('some_view_name'), q.urlencode())
# '/some_url/?value_with_special_chars=hello%3Dw%23rld%3F&some_list=1&some_list=2&some_list=3&some_list=4&some_key=some_value'
Чтобы использовать это в шаблонах, вам нужно создать собственный тег шаблона
Ответ 4
Ни один из исходных ответов не касается связанных с разрешением проблем URL-адресов в коде представления. Для будущих пользователей, если вы пытаетесь это сделать, используйте kwargs, например:
reverse('myviewname', kwargs={'pk': value})
Ответ 5
Ответ, который использовал urllib, действительно хорош, однако, хотя он пытался избежать конкатенации строк, он использовал его в path + '?' + urllib.urlencode(kwargs)
. Я считаю, что это может создать проблемы, когда path
уже имеет некоторые parmas запросов.
Измененная функция будет выглядеть так:
def url_with_querystring(url, **kwargs):
url_parts = list(urlparse.urlparse(url))
query = dict(urlparse.parse_qsl(url_parts[4]))
query.update(kwargs)
url_parts[4] = urllib.urlencode(query)
return urlparse.urlunparse(url_parts)
Ответ 6
Рабочая вариация предыдущих ответов и мой опыт работы с этим материалом.
from django.urls import reverse
from django.utils.http import urlencode
def build_url(*args, **kwargs):
params = kwargs.pop('params', {})
url = reverse(*args, **kwargs)
if params:
url += '?' + urlencode(params)
return url
Как использовать:
>>> build_url('products-detail', kwargs={'pk': 1}, params={'category_id': 2})
'/api/v1/shop/products/1/?category_id=2'