How do I construct a Django reverse/url using query args?

后端 未结 6 459
长发绾君心
长发绾君心 2020-12-13 04:25

I have URLs like http://example.com/depict?smiles=CO&width=200&height=200 (and with several other optional arguments)

My urls.py contains:

ur         


        
相关标签:
6条回答
  • 2020-12-13 04:42

    Building an url with query string by string concatenation as suggested by some answers is as bad idea as building SQL queries by string concatenation. It is complicated, unelegant and especially dangerous with a user provided (untrusted) input. Unfortunately Django does not offer an easy possibility to pass query parameters to the reverse function.

    Python standard urllib however provides the desired query string encoding functionality.

    In my application I've created a helper function:

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

    Then I call it in the view as follows:

    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
    

    Please note the proper encoding of special characters like space and exclamation mark!

    0 讨论(0)
  • 2020-12-13 04:45

    I recommend to use builtin django's QueryDict. It also handles lists properly. End automatically escapes some special characters (like =, ?, /, '#'):

    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'
    

    To use this in templates you will need to create custom template tag

    0 讨论(0)
  • 2020-12-13 04:54

    Working variation of previous answers and my experience with dealing this stuff.

    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
    

    How to use:

    >>> build_url('products-detail', kwargs={'pk': 1}, params={'category_id': 2})
    '/api/v1/shop/products/1/?category_id=2'
    
    0 讨论(0)
  • 2020-12-13 04:58

    Your regular expresion has no place holders (that's why you are getting NoReverseMatch):

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

    You could do it like this:

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

    URLconf search does not include GET or POST parameters

    Or if you wish to use {% url %} tag you should restructure your url pattern to something like

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

    then you could do something like

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

    Follow-up:

    Simple example for custom 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))
    

    You could use this tag in your templates like so:

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

    and hopefully it should output something like

    /depict?width=200&height=200&name=SomeName
    
    0 讨论(0)
  • 2020-12-13 05:03

    Neither of the original answers addresses the related issue resolving URLs in view code. For future searchers, if you are trying to do this, use kwargs, something like:

    reverse('myviewname', kwargs={'pk': value})
    
    0 讨论(0)
  • 2020-12-13 05:03

    The answer that used urllib is indeed good, however while it was trying to avoid strings concatenation, it used it in path + '?' + urllib.urlencode(kwargs). I believe this may create issues when the path has already some query parmas.

    A modified function would look like:

    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)
    
    0 讨论(0)
提交回复
热议问题