Comment construire un Django reverse / url à l'aide de query args?

j'ai des URLs comme http://example.com/depict?smiles=CO&width=200&height=200 (et avec plusieurs autres arguments optionnels)

Mon urls.py contient:

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

je peux aller à cette URL et obtenir le PNG 200x200 qui a été construit, donc je sais que la partie fonctionne.

dans mon modèle du " cansmi.cansmi "réponse je veux construire une URL pour le modèle nommé" cyclops-depict " donné certains paramètres de requête. Je pensais que je pourrais faire

{% url cyclope-dépeignent des sourires=input_smiles width=200, height=200 %}

où "input_smiles" est une entrée dans le modèle via un formulaire de soumission. Dans ce cas, c'est la chaîne "CO" et j'ai pensé qu'elle créerait une URL comme celle du haut.

ce template échoue avec un TemplateSyntaxError:

a pris une exception lors du rendu: inverse pour 'cyclops-depict' avec arguments '() ' et mots clés arguments '{'sourire': u CO', 'height': 200, largeur: 200} " introuvable.

c'est un message d'erreur assez courant à la fois ici sur StackOverflow et ailleurs. Dans chaque cas que j'ai trouvé, les gens les utilisaient avec des paramètres dans le chemin D'URL regexp, ce qui n'est pas le cas où j'ai où les paramètres vont dans la requête.

cela signifie Que je suis en train de faire le mal. Comment dois-je faire? C'est-à-dire que je veux construire L'URL complète, y compris les paramètres de chemin et de requête, en utilisant quelque chose dans le modèle.

Pour référence,

% 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
demandé sur John Carter 2010-05-06 07:31:05

6 réponses

votre expression régulière n'a pas de porte-place (c'est pourquoi vous obtenez NoReverseMatch):

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

Vous pourriez le faire comme ceci:

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

URLconf de recherche de ne pas inclure des paramètres GET ou POST

ou si vous souhaitez utiliser la balise {% url %} vous devez restructurer votre patron d'url en quelque chose comme

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

ensuite, vous pourriez faire quelque chose comme

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

Suivi:

exemple Simple pour étiquette personnalisée:

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

Vous pouvez utiliser cette balise dans vos modèles comme ceci:

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

et avec un peu de chance il devrait sortir quelque chose comme

/depict?width=200&height=200&name=SomeName
20
répondu Davor Lucic 2010-05-06 14:53:09

construire une url avec une chaîne de requête par concaténation de chaîne comme suggéré par certaines réponses est aussi mauvaise idée que construire des requêtes SQL par concaténation de chaîne. Il est compliqué, peu élégant et particulièrement dangereux avec un utilisateur fourni (non fiable) entrée. Malheureusement Django n'offre pas une possibilité facile de passer des paramètres de requête à inverse fonction.

Python standard urllib fournit cependant le codage de chaîne de requête souhaité fonctionnalité.

dans mon application j'ai créé une fonction helper:

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

Puis-je l'appeler dans la vue comme suit:

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

veuillez noter le bon encodage des caractères spéciaux comme espace et point d'exclamation!

44
répondu geekQ 2011-03-17 16:05:28

je vous recommande d'utiliser builtin django QueryDict. Il gère également les listes correctement. Fin automatiquement échappe à certains caractères spéciaux (comme =,?, /, '#'):

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'

pour l'utiliser dans les modèles, vous aurez besoin de créer la balise de modèle personnalisé

10
répondu imposeren 2015-03-22 08:44:20

ni l'une ni l'autre des réponses originales n'aborde la question connexe de la résolution des URLs dans le code de vue. Pour les futurs chercheurs, si vous essayez pour ce faire, utilisez kwargs, quelque chose comme:

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

8
répondu Aitch 2013-01-02 10:18:26

La réponse qui a utilisé urllib est en effet de bonnes, cependant, alors qu'il tentait d'éviter de concaténation de chaînes de caractères, il l'a utilisé dans path + '?' + urllib.urlencode(kwargs). Je crois que cela peut créer des problèmes lors de l' path a déjà quelques parmes d'interrogation.

une fonction modifiée ressemblerait à:

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
répondu Nour Chawich 2015-11-11 08:27:45

variation de travail des réponses précédentes et de mon expérience avec le traitement de ce genre de choses.

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

utilisation:

>>> build_url('products-detail', kwargs={'pk': 1}, params={'category_id': 2})
'/api/v1/shop/products/1/?category_id=2'
0
répondu michal-michalak 2018-09-15 11:29:00