ฉันจะสร้าง Django Reverse/url โดยใช้ args แบบสอบถามได้อย่างไร

ฉันมี URL เช่น http://example.com/depict?smiles=CO&width=200&height=200 (และอาร์กิวเมนต์ทางเลือกอื่นๆ อีกหลายข้อ)

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-depict" โดยให้พารามิเตอร์การค้นหาบางตัว ฉันคิดว่าฉันทำได้

{% url ไซคลอปส์-depict ยิ้ม=input_smiles ความกว้าง=200 ความสูง=200 %}

โดยที่ "input_smiles" เป็นการป้อนข้อมูลไปยังเทมเพลตผ่านการส่งแบบฟอร์ม ในกรณีนี้คือสตริง "CO" และฉันคิดว่าจะสร้าง URL แบบที่อยู่ด้านบน

เทมเพลตนี้ล้มเหลวด้วย TemplateSyntaxError:

พบข้อยกเว้นขณะเรนเดอร์: ย้อนกลับสำหรับ 'cyclops-depict' พร้อมอาร์กิวเมนต์ '()' และอาร์กิวเมนต์คำหลัก '{'smiles': u'CO', 'height': 200, 'width': 200}' ไม่พบ

นี่เป็นข้อความแสดงข้อผิดพลาดที่พบบ่อยทั้งที่นี่ใน StackOverflow และที่อื่นๆ ในทุกกรณีที่ฉันพบ ผู้คนใช้พารามิเตอร์เหล่านี้กับพารามิเตอร์ใน regexp เส้นทาง 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.

person Andrew Dalke    schedule 06.05.2010    source แหล่งที่มา
comment
ฉันสร้างคำขอคุณลักษณะ: code.djangoproject.com/ticket/25582   -  person guettli    schedule 21.10.2015


คำตอบ (6)


การแสดงออกปกติของคุณไม่มีตัวยึดตำแหน่ง (นั่นคือเหตุผลที่คุณได้รับ 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
person Davor Lucic    schedule 06.05.2010
comment
นั่นค่อนข้างไม่สวยงาม ซึ่งเป็นสาเหตุที่ฉันคิดว่าต้องมีวิธีแก้ปัญหาที่ดีกว่านี้ พารามิเตอร์บางตัวมาจากการป้อนแบบฟอร์ม นิพจน์เทมเพลตจริงจะเป็น {% url cyclops-depict %}?smiles={{input_smiles}}&width={{size}}&height={{size}} นั่นเข้าใจและอธิบายได้ยากกว่า {% query-url cyclops-depict smiles=input_smiles width=size height=size %} ที่ไม่ถูกต้อง/สมมุติฐาน แน่นอนว่าการมีรูปแบบใน URL นั้นเป็นไปได้ แต่พารามิเตอร์ 7 จาก 8 รายการนั้นเป็นทางเลือก และไม่มีการเรียงลำดับตามธรรมชาติ ทำให้ค่อนข้างถูกบังคับ (Grrr. และ Django น่าจะเหมาะสำหรับผู้ที่ชอบความสมบูรณ์แบบ) - person Andrew Dalke; 06.05.2010
comment
หากคุณต้องการสรุปตรรกะสำหรับการสร้าง URL คุณสามารถเขียน [custom templatetag] [1] ของคุณเองได้ ทำให้ต้องใช้พารามิเตอร์เช่น entry หรือแม้แต่บริบทที่สมบูรณ์และส่งคืน URL ที่สร้างขึ้น ด้วยวิธีนี้ คุณสามารถจำลองแท็ก url และมีไวยากรณ์ที่คุณต้องการได้... [1]: docs.djangoproject.com/en/dev/howto/custom-template-tags/ - person Davor Lucic; 06.05.2010
comment
ฉันจะกลับมาที่โครงการนี้ สิ่งหนึ่งคือฉันกำลังสอนสิ่งนี้ให้กับนักพัฒนาที่ไม่ใช่ซอฟต์แวร์ (พวกเขาเป็นนักเคมีเชิงคำนวณที่ทำการเขียนโปรแกรมบางอย่าง) และฉันไม่ต้องการอธิบายทั้งหมดนี้ ฉันจะต้องคิดเกี่ยวกับเรื่องนี้อีกสักหน่อย ขอบคุณสำหรับการติดตาม! - person Andrew Dalke; 13.05.2010

การสร้าง URL ด้วยสตริงการสืบค้นโดยการต่อสตริงตามที่แนะนำโดยคำตอบบางข้อนั้นเป็นความคิดที่ไม่ดีเท่ากับการสร้างการสืบค้น SQL ด้วยการต่อสตริง มันซับซ้อน ไม่สง่างาม และเป็นอันตรายอย่างยิ่งกับข้อมูลที่ผู้ใช้ให้มา (ไม่น่าเชื่อถือ) น่าเสียดายที่ Django ไม่มีความเป็นไปได้ที่ง่ายในการส่งพารามิเตอร์การสืบค้นไปยัง reverse ฟังก์ชัน

urllib มาตรฐาน Python มีฟังก์ชันการเข้ารหัสสตริงข้อความค้นหาที่ต้องการ

ในแอปพลิเคชันของฉัน ฉันได้สร้างฟังก์ชันตัวช่วย:

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

โปรดสังเกตการเข้ารหัสอักขระพิเศษ เช่น ช่องว่างและเครื่องหมายอัศเจรีย์อย่างเหมาะสม!

person geekQ    schedule 17.03.2011
comment
เห็นด้วย ดีกว่าการต่อข้อมูลแบบธรรมดา - person Davor Lucic; 28.03.2011
comment
ฉันต้องการสร้าง URL จากภายในเทมเพลต ถ้าฉันเข้าใจคุณถูกต้อง แม้ว่าสิ่งนี้จะช่วยสร้าง URL ได้ แต่ก็ยังต้องมีตะขอแท็กเทมเพลต - person Andrew Dalke; 18.04.2011
comment
@Andrew Dalke คุณพูดถูก คุณยังคงต้องใช้แท็กที่กำหนดเองพร้อมกับการใช้งานตาม urllib.urlencode - person geekQ; 20.04.2011
comment
ตอนนี้เราหกปีแล้ว ยังไม่มีวิธีที่เหมาะสมใน reverse ของ Django เพื่อรวมพารามิเตอร์การสืบค้นหรือไม่ - person physicalattraction; 23.01.2017
comment
โดยทั่วไปฉันเห็นด้วย แต่ในกรณีของพารามิเตอร์คงที่ การต่อสตริงจะดำเนินการ - person x-yuri; 29.06.2018

ฉันแนะนำให้ใช้ QueryDict ของ django นอกจากนี้ยังจัดการรายการต่างๆ ได้อย่างถูกต้องอีกด้วย 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'

หากต้องการใช้ในเทมเพลต คุณจะต้องสร้างแท็กเทมเพลตที่กำหนดเอง

person imposeren    schedule 24.12.2014

ไม่มีคำตอบเดิมใดที่กล่าวถึงปัญหาที่เกี่ยวข้องในการแก้ไข URL ในโค้ดมุมมอง สำหรับผู้ค้นหาในอนาคต หากคุณกำลังพยายามทำเช่นนี้ ให้ใช้ kwargs เช่น:

reverse('myviewname', kwargs={'pk': value})
person Aitch    schedule 02.01.2013
comment
การย้อนกลับด้วย kwargs ใช้ได้กับพารามิเตอร์พาธเท่านั้น ไม่ใช่พารามิเตอร์การสืบค้น - person Pace; 30.05.2013
comment
คำชี้แจงที่ดี @Pace ฉันไม่รู้ว่า... ขอบคุณ! - person allexiusw; 05.03.2021

คำตอบที่ใช้ urllib นั้นดีจริง ๆ อย่างไรก็ตามในขณะที่พยายามหลีกเลี่ยงการต่อสตริง แต่ก็ใช้ใน path + '?' + urllib.urlencode(kwargs) ฉันเชื่อว่านี่อาจสร้างปัญหาเมื่อ path มีปาร์ม่าข้อความค้นหาอยู่แล้ว

ฟังก์ชั่นที่แก้ไขจะมีลักษณะดังนี้:

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)
person Nour Wolf    schedule 11.11.2015

รูปแบบการทำงานของคำตอบก่อนหน้าและประสบการณ์ของฉันในการจัดการกับสิ่งนี้

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'
person michal-michalak    schedule 15.09.2018