Including a querystring in a django.core.urlresolvers reverse() call


Django Problem Overview

I'm trying to reverse a named URL and include a querystring in it. Basically, I've modified the login function, and I want to send ?next= in it.

Here's what I'm doing now: reverse(name) + "?next=" + reverse(redirect)

Here's what I'd like to do: reverse(name, kwargs = { 'next':reverse(redirect) } )

My URL for the login page (just as an example) looks like this:

url(r'^login/', custom_login, name = 'login'),

So how do I modify this whole thing (or call it) to include the next without having to concatenate it? It feels like an iffy solution at best.

Django Solutions

Solution 1 - Django

You can't capture GET parameters in the url confs, so your method is correct.

I generally prefer string formatting but it's the same thing.
"%s?next=%s" % (reverse(name), reverse(redirect))

> The URLconf searches against the > requested URL, as a normal Python > string. This does not include GET or > POST parameters, or the domain name.

Solution 2 - Django

I just made my own utility function like the one asked in the question:

from django.utils.http import urlencode

def my_reverse(viewname, kwargs=None, query_kwargs=None):
    Custom reverse to add a query string after the url
    Example usage:
    url = my_reverse('my_test_url', kwargs={'pk':}, query_kwargs={'next': reverse('home')})
    url = reverse(viewname, kwargs=kwargs)

    if query_kwargs:
        return f'{url}?{urlencode(query_kwargs)}'

    return url

Solution 3 - Django

I think it's better to wrap Django's reverse method to expose this API. Here's some simple code to do it:

from django.core.urlresolvers import reverse as django_reverse

def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
    Wrapper of django.core.urlresolvers.reverse that attaches arguments in kwargs as query string parameters
    if kwargs:
        return '%s?%s' % (django_reverse(viewname, urlconf, args, None, prefix, current_app), \
                        '&'.join(['%s=%s' % (k,v) for k,v in kwargs.items()]))
        return django_reverse(viewname, urlconf, args, kwargs, prefix, current_app)

Put this code into some utility or common app that only depends on Django, then instead of importing django.core.urlresolvers.reverse just import myproject.myutils.urlresolvers.reverse

Solution 4 - Django

I was troubled with the same question and found this link. Apparently, your solution isn't bad designed at all. According to the ticket discussion Django won't provide this functionality.

You could use urlobject or furl.

The other way, is to use your own function to do this, in a much more cleaner way. Here's the one stated in the discussion

from django.utils.http import urlencode
from django.core.urlresolvers import reverse as original_reverse

def reverse(*args, **kwargs):
    get = kwargs.pop('get', {})
    url = original_reverse(*args, **kwargs)

    if get:
        url += '?' + urlencode(get)

    return url

In the question's case, it can be used the following way

from [myfunctions] import reverse
reverse('login', get={next: reverse(redirect)})

Solution 5 - Django

To keep the query optional, you can wrap Django's reverse function with your own function that also handles the query, allowing for other proper handling of the reverse function.

Creating a Proper Request - Note that the query_kwargs is optional, so you don't have to send it

# from a views in
def sendingView(request, truckID, fleetSlug):
  #in the GET or POST
  return HttpResponseRedirect(reverse('subAppName:urlViewName', 
                                      query_kwargs={'queries': goHere}

# from a template in specificTemplate.html
<a class="nav-link" href="{% url 'subAppName:urlViewName' kwarg1=kwarg1 kwarg2=kwarg2 … query_kwargs={'dict':here} %}">Link</a>

#from a model in
class Truck(models.Model):
  name = models.CharField(…)
  def get_absolute_wi_url(self):
    return reverse('subAppName:urlViewName', kwargs={'kwarg1':kwarg1,'kwarg2':kwarg2})

In file (based on docs) for (1.11 and up?)


from django.core.urlresolvers import reverse as django_reverse

def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None, query_kwargs=None):
  Wrapper of django.core.urlresolvers.reverse that attaches arguments in kwargs as query string parameters
  if query_kwargs:
    return '%s?%s' % (django_reverse(viewname, urlconf, args, kwargs, current_app), \
                    '&'.join(['%s=%s' % (k,v) for k,v in query_kwargs.items()]))
    return django_reverse(viewname, urlconf, args, kwargs, current_app)

In the urls conf

app_name = 'subAppName'
urlpatterns = [
  url(r'^(?P<kawrg1>[a-zA-Z0-9]+)/(?P<kawrg2>[a-zA-Z0-9]+)/path/to/here/$', views.urlViewFunctionName, name='urlViewName'),

And gaining access to the query

#in a view
def urlViewFunctionName(request, kwarg1, kwarg2):   
  if request.GET.get('submittedData'):
    submittedQuery = request.GET.get('submittedData')
  submittedQuery = None
return render(request, 'trucks/weeklyInspectionSuccess.html', {
  'truck': truck,
  'submittedQuery': submittedQuery

#in a template
<div class="container">  
  Success for {{kwarg1}}


All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBrian HicksView Question on Stackoverflow
Solution 1 - DjangoYuji 'Tomita' TomitaView Answer on Stackoverflow
Solution 2 - DjangoDaniel BackmanView Answer on Stackoverflow
Solution 3 - DjangoAlan IllingView Answer on Stackoverflow
Solution 4 - DjangoNodiel Clavijo LleraView Answer on Stackoverflow
Solution 5 - Djangochris FrisinaView Answer on Stackoverflow