2010-05-06 1 views
24

У меня есть URL-адреса, как http://example.com/depict?smiles=CO&width=200&height=200 (и с несколькими другими дополнительными аргументами)Как создать Django reverse/url с использованием запросов args?

Мой urls.py содержит:

urlpatterns = patterns('', 
    (r'^$', 'cansmi.index'), 
    (r'^cansmi$', 'cansmi.cansmi'), 
    url(r'^depict$', cyclops.django.depict, name="cyclops-depict"), 

Я могу пойти на этот URL и получить 200x200 PNG, который был построен, так что я знаю эта часть работает.

В моем шаблоне из ответа «cansmi.cansmi» я хочу создать URL-адрес для именованного шаблона «cyclops-pictict» с учетом некоторых параметров запроса. Я думал, что я мог бы сделать

{% url cyclops-depict smiles=input_smiles width=200 height=200 %}

где «input_smiles» является ввод в шаблон с помощью отправки формы. В этом случае это строка «CO», и я думал, что она создаст URL-адрес, подобный тому, который находится сверху.

Этот шаблон не может с TemplateSyntaxError:

Caught an exception while rendering: Reverse for 'cyclops-depict' with arguments '()' and keyword arguments '{'smiles': u'CO', 'height': 200, 'width': 200}' not found.

Это довольно общее сообщение об ошибке, как здесь, на StackOverflow и в других местах. В каждом случае, я нашел, люди использовали их с параметрами в 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. 
+0

Я создал запрос функции: https://code.djangoproject.com/ticket/25582 – guettli

ответ

18

Ваш обычный expresion не имеет заполнителей (именно поэтому вы получаете NoReverseMatch):

url(r'^depict$', cyclops.django.depict, name="cyclops-depict"), 

Вы можете сделать это следующим образом:

{% url cyclops-depict %}?smiles=CO&width=200&height=200 

URLconf search does not include GET or POST parameters

Или, если вы хотите использовать {% 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 cyclops-pictict%}? Smiles = {{input_smiles}} & width = {{size}} & height = {{size}}. Это сложнее понять и объяснить, чем недействительный/гипотетический {% query-url cyclops-pictict smiles = input_smiles width = size height = size%}. Разумеется, наличие шаблонов в URL-адресе возможно, но 7 из 8 параметров являются необязательными, и нет естественного упорядочения, что делает его довольно принудительным. (Grrr. И Django должен быть для перфекционистов.) –

+0

Если вы хотите инкапсулировать логику построения URL-адресов, вы можете просто написать свой собственный [custom templatetag] [1]. Заставьте его принимать такие параметры, как «запись» или даже полный контекст и возвращаемый построенный URL. Таким образом, вы могли бы даже эмулировать тэг 'url' и иметь синтаксис, который вам нравится. [1]: http://docs.djangoproject.com/ru/dev/howto/custom-template-tags/#custom- template-tags-and-filters –

+0

Я возвращаюсь к этому проекту. Одна вещь заключается в том, что я преподаю это разработчикам, не использующим программное обеспечение (они - химики-вычислители, которые занимаются программированием), и я не хочу все это объяснять. Мне придется подумать об этом еще немного. Спасибо за продолжение! –

42

Построение URL со строкой запроса путем конкатенации как предложено некоторыми ответы - это плохая идея, как создание SQL-запросов путем конкатенации строк. Это сложный, неудобный и особенно опасный с предоставленным пользователем (ненадежным) вводом. К сожалению, Django не предлагает простой возможности передать параметры запроса в функцию reverse.

Стандарт Python urllib однако обеспечивает требуемую функциональность кодировки строки запроса.

В моем приложении я создал вспомогательную функцию:

def url_with_querystring(path, **kwargs): 
    return path + '?' + urllib.urlencode(kwargs) 

Тогда я назвал его в представлении следующим образом:

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 

Пожалуйста, обратите внимание на правильную кодировку специальных символов, таких как пространство и восклицательный знак!

+0

Согласовано, лучше, чем простая конкатенация. –

+1

Я хотел бы создать URL-адрес изнутри шаблона. Если я понимаю вас правильно, хотя это помогает сделать URL-адрес, ему все равно нужен крючок шаблона. –

+0

@Andrew Dalke Вы правы, вам все равно нужно реализовать собственный тег с реализацией на основе urllib.urlencode – geekQ

11

Ни в одном из исходных ответов не рассматривается связанная с этим проблема, разрешающая URL-адреса в коде просмотра. Для будущих искателей, если вы пытаетесь сделать это, используйте kwargs, что-то вроде:

reverse('myviewname', kwargs={'pk': value})

+2

Это должен быть принятый ответ. – Amyth

+40

Реверс с kwargs работает только для параметров пути, а не параметров запроса. – Pace

8

Я рекомендую использовать встроенное Джанго QueryDict. Он также правильно обрабатывает списки.Конец автоматически ускользает некоторые специальные символы (например, =, ?, /, «#»):

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

ответ, который используется 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) 
Смежные вопросы