2010-05-06 22 views
24

Tôi có URL như http://example.com/depict?smiles=CO&width=200&height=200 (và với một số đối số tùy chọn khác)Làm thế nào để xây dựng một Django ngược/url bằng cách sử dụng truy vấn args?

urls.py My chứa:

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

tôi có thể đi đến URL và nhận được 200x200 PNG đã được xây dựng, vì vậy tôi biết phần đó hoạt động.

Trong mẫu của tôi từ phản hồi "cansmi.cansmi", tôi muốn tạo URL cho mẫu có tên "cyclops-depict" được cung cấp một số tham số truy vấn. Tôi nghĩ tôi có thể làm

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

trong đó "input_smiles" là đầu vào cho mẫu thông qua gửi biểu mẫu. Trong trường hợp này, đó là chuỗi "CO" và tôi nghĩ rằng nó sẽ tạo một URL giống như URL ở trên cùng.

mẫu này không thành công với một TemplateSyntaxError:

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

Đây là một thông báo lỗi khá phổ biến cả ở đây trên StackOverflow và các nơi khác. Trong mọi trường hợp tôi tìm thấy, mọi người đã sử dụng chúng với các tham số trong đường dẫn URL regexp, đó không phải là trường hợp tôi có nơi các tham số đi vào truy vấn.

Điều đó có nghĩa là tôi đang làm sai. Làm thế nào để tôi làm điều đó đúng không? Đó là, tôi muốn xây dựng URL đầy đủ, bao gồm các tham số đường dẫn và truy vấn, sử dụng một cái gì đó trong mẫu.

Để tham khảo,

% 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

Tôi tạo ra một yêu cầu tính năng: https://code.djangoproject.com/ticket/25582 – guettli

Trả lời

18

cụm từ thông dụng của bạn không có giữ chỗ (đó là lý do tại sao bạn đang nhận được NoReverseMatch):

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

Bạn có thể làm điều đó như thế này:

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

URLconf search does not include GET or POST parameters

Hoặc nếu bạn muốn sử dụng {% url%} tag bạn nên tái cấu trúc mẫu url của bạn để một cái gì đó giống như

r'^depict/(?P<width>\d+)/(?P<height>\d+)/(?P<smiles>\w+)$' 

sau đó bạn có thể làm một cái gì đó giống như

{% url cyclops-depict 200 200 "CO" %} 

Follow-up :

Ví dụ đơn giản cho thẻ tùy chỉnh:

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)) 

Bạn có thể sử dụng thẻ này trong các mẫu của bạn như vậy:

{% myurl width=200 height=200 name=SomeName %} 

và hy vọng nó nên ra một cái gì đó giống như

/depict?width=200&height=200&name=SomeName 
+2

Đó là thay vì thanh nha, đó là lý do tại sao tôi nghĩ rằng phải có một giải pháp tốt hơn. Một số tham số đến từ mục nhập biểu mẫu. Biểu thức mẫu thực tế sẽ là {% url cyclops-depict%}? Smiles = {{input_smiles}} & width = {{size}} & height = {{size}}. Đó là khó hiểu và giải thích hơn {% query-url cyclops-depict smiles = input_smiles width = size height = size%} không hợp lệ/giả định. Có các mẫu trong URL là tất nhiên có thể nhưng 7 trong số 8 tham số là tùy chọn và không có thứ tự tự nhiên, khiến cho nó bị ép buộc. (Grrr. Và Django được cho là dành cho người cầu toàn.) –

+0

Nếu bạn muốn đóng gói logic để tạo URL, bạn có thể viết [custom templatetag] [1]. Làm cho nó lấy các tham số như 'entry' hoặc thậm chí là một bối cảnh hoàn chỉnh và trả về URL được xây dựng. Bằng cách này, bạn thậm chí có thể mô phỏng thẻ 'url' và có cú pháp bạn thích .. [1]: http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#custom- template-tags-and-filters –

+0

Tôi đang quay lại dự án này. Một điều là tôi đang dạy điều này cho các nhà phát triển không phải phần mềm (họ là những nhà hóa học tính toán làm một số lập trình) và tôi không muốn giải thích tất cả điều này. Tôi sẽ phải suy nghĩ về điều này một số chi tiết. Cảm ơn đã theo lên! –

42

Xây dựng một url với chuỗi truy vấn bằng cách nối chuỗi theo đề nghị của một số câu trả lời là ý tưởng tồi khi xây dựng các truy vấn SQL bằng chuỗi nối. Nó phức tạp, không phân biệt và đặc biệt nguy hiểm với đầu vào do người dùng cung cấp (không đáng tin cậy). Thật không may Django không cung cấp một khả năng dễ dàng để chuyển các tham số truy vấn đến hàm reverse.

Chuẩn Python urllib tuy nhiên cung cấp chức năng mã hóa chuỗi truy vấn mong muốn.

Trong ứng dụng của tôi, tôi đã tạo một hàm helper:

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

Sau đó, tôi gọi nó là trong giao diện như sau:

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 

Xin lưu ý mã hóa thích hợp của các nhân vật đặc biệt như không gian và dấu chấm than!

+0

Đồng ý, tốt hơn sau đó đồng bằng nối. –

+1

Tôi muốn tạo URL từ bên trong mẫu. Nếu tôi hiểu bạn đúng, trong khi điều này giúp tạo URL, nó vẫn cần móc thẻ mẫu. –

+0

@Andrew Dalke Bạn nói đúng, bạn sẽ vẫn cần triển khai thẻ tùy chỉnh với triển khai dựa trên urllib.urlencode – geekQ

11

Không có câu trả lời gốc nào giải quyết được vấn đề liên quan giải quyết URL trong mã xem. Đối với những người tìm kiếm trong tương lai, nếu bạn đang cố gắng để làm điều này, sử dụng kwargs, một cái gì đó như:

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

+2

Đây phải là câu trả lời được chấp nhận. – Amyth

+40

đảo ngược với kwargs chỉ hoạt động cho các tham số đường dẫn, không phải tham số truy vấn. – Pace

8

Tôi khuyên bạn nên sử dụng được xây dựng trong django của QueryDict. Nó cũng xử lý danh sách đúng cách.Kết thúc tự động thoát một số ký tự đặc biệt (như =, ?, /, '#'):

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' 

Để sử dụng trong các mẫu, bạn sẽ cần phải tạo ra tùy chỉnh mẫu thẻ

4

Câu trả lời mà dùng urllib thực sự là tốt, tuy nhiên trong khi nó đã cố gắng để tránh chuỗi nối, nó được sử dụng nó trong path + '?' + urllib.urlencode(kwargs). Tôi tin rằng điều này có thể tạo ra các vấn đề khi path đã có một số parmas truy vấn.

Một chức năng sửa đổi sẽ như thế nào:

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)