webentwicklung-frage-antwort-db.com.de

Wie erstelle ich ein Django-Reverse/eine Django-URL mithilfe von Query Args?

Ich habe URLs wie http://example.com/depict?smiles=CO&width=200&height=200 (und mit mehreren anderen optionalen Argumenten)

Meine urls.py enthält:

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

Ich kann zu dieser URL gehen und das 200x200 PNG erhalten, das konstruiert wurde, also weiß ich, dass Teil arbeitet.

In meiner Vorlage aus der Antwort "cansmi.cansmi" möchte ich eine URL für die benannte Vorlage "cyclops-depict" mit bestimmten Abfrageparametern erstellen. Ich dachte, ich könnte tun

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

dabei ist "input_smiles" eine Eingabe in die Vorlage über eine Formularübermittlung. In diesem Fall ist es die Zeichenfolge "CO" und ich dachte, es würde eine URL wie oben erstellen.

Diese Vorlage schlägt mit einem TemplateSyntaxError fehl:

Beim Rendern ist eine Ausnahme aufgetreten: Reverse für 'Cyclops-Darstellung' mit Argumenten '()' und Keyword-Argumenten '{' lächelt ': u'CO', 'Höhe': 200, 'Breite': 200} 'nicht gefunden.

Dies ist eine häufige Fehlermeldung, sowohl hier auf StackOverflow als auch anderswo. In jedem Fall habe ich festgestellt, dass die Benutzer sie mit Parametern im URL-Pfad regexp verwendeten. Dies ist nicht der Fall, in dem die Parameter in die Abfrage eingehen.

Das heißt, ich mache es falsch. Wie mache ich es richtig? Das heißt, ich möchte die vollständige URL einschließlich der Pfad- und Abfrageparameter mithilfe eines Elements in der Vorlage erstellen.

Als Referenz,

% 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.
27
Andrew Dalke

Ihr regulärer Ausdruck hat keine Platzhalter (deshalb erhalten Sie NoReverseMatch):

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

Du könntest es so machen:

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

Die URLconf-Suche enthält keine GET- oder POST -Parameter

Oder wenn Sie das Tag {% url%} verwenden möchten, sollten Sie Ihr URL-Muster auf etwas Ähnliches umstrukturieren 

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

dann könntest du sowas machen 

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

Follow-up:

Einfaches Beispiel für ein benutzerdefiniertes Tag:

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

Sie können dieses Tag in Ihren Vorlagen wie folgt verwenden:

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

und hoffentlich sollte so etwas ausgegeben werden

/depict?width=200&height=200&name=SomeName
20
Davor Lucic

Das Erstellen einer URL mit einer Abfragezeichenfolge durch eine Zeichenfolgenverkettung, wie in einigen Antworten vorgeschlagen, ist ebenso eine schlechte Idee wie das Erstellen von SQL-Abfragen durch Zeichenfolgenverkettung. Es ist kompliziert, unelegant und besonders gefährlich bei einer vom Benutzer bereitgestellten (nicht vertrauenswürdigen) Eingabe. Leider bietet Django keine einfache Möglichkeit, Abfrageparameter an die Funktion reverse zu übergeben.

Der Python-Standard urllib bietet jedoch die gewünschte Codierungsfunktion für Abfragezeichenfolgen.

In meiner Anwendung habe ich eine Hilfsfunktion erstellt:

def url_with_querystring(path, **kwargs):
    return path + '?' + urllib.urlencode(kwargs) # for Python 3, use urllib.parse.urlencode instead

Dann nenne ich es in der Ansicht wie folgt:

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

Bitte beachten Sie die richtige Kodierung von Sonderzeichen wie Leerzeichen und Ausrufezeichen!

44
geekQ

Ich empfehle, eingebaute Django's QueryDict zu verwenden. Es behandelt auch Listen richtig. Ende entgeht automatisch einigen Sonderzeichen (wie =, ?, /, '#'):

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'

Um dies in Vorlagen verwenden zu können, müssen Sie ein benutzerdefiniertes Vorlagen-Tag erstellen

12
imposeren

Keine der ursprünglichen Antworten adressiert das zugehörige Problem bei der Auflösung von URLs im Ansichtscode. Verwenden Sie für zukünftige Sucher Kwargs, etwa:

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

9
Aitch

Die Antwort, die urllib verwendet, ist in der Tat gut, aber während es versuchte, die Verkettung von Strings zu vermeiden, wurde es in path + '?' + urllib.urlencode(kwargs) verwendet. Ich glaube, dass dies zu Problemen führen kann, wenn die path bereits einige Abfrage-Parmas hat.

Eine modifizierte Funktion würde folgendermaßen aussehen:

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)
5
Nour Chawich

Arbeitsvariante früherer Antworten und meine Erfahrungen mit diesem Zeug.

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

Wie benutzt man:

>>> build_url('products-detail', kwargs={'pk': 1}, params={'category_id': 2})
'/api/v1/shop/products/1/?category_id=2'
0
michal-michalak