EvdB
EvdB

Reputation: 1769

Altering one query parameter in a url (Django)

I have a search page that takes a variety of parameters. I want to create a new URL by just altering one parameter in the query. Is there an easy way to do this - something like:

# example request url
http://example.com/search?q=foo&option=bar&option2=baz&change=before

# ideal template code
{% url_with change 'after' %}

# resulting url
http://example.com/search?q=foo&option=bar&option2=baz&change=after

So this would take the request url, alter one query parameter and then return the new url. Similar to what can be achieved in Perl's Catalyst using $c->uri_with({change => 'after'}).

Or is there a better way?

[UPDATED: removed references to pagination]

Upvotes: 21

Views: 13344

Answers (7)

Tom Christie
Tom Christie

Reputation: 33911

So, write a template tag around this:

from urlparse import urlparse, urlunparse
from django.http import QueryDict

def replace_query_param(url, attr, val):
    (scheme, netloc, path, params, query, fragment) = urlparse(url)
    query_dict = QueryDict(query).copy()
    query_dict[attr] = val
    query = query_dict.urlencode()
    return urlunparse((scheme, netloc, path, params, query, fragment))

For a more comprehensive solution, use Zachary Voase's URLObject 2, which is very nicely done.

Note: The urlparse module is renamed to urllib.parse in Python 3.

Upvotes: 20

allanberry
allanberry

Reputation: 7775

This worked pretty well for me. Allows you to set any number of parameters in the URL. Works nice for a pager, while keeping the rest of the query string.

from django import template
from urlobject import URLObject

register = template.Library()

@register.simple_tag(takes_context=True)
def url_set_param(context, **kwargs):
    url = URLObject(context.request.get_full_path())
    path = url.path
    query = url.query
    for k, v in kwargs.items():
        query = query.set_param(k, v)
    return '{}?{}'.format(path, query)

Then in the template:

<a href="{% url_set_param page=last %}">

Upvotes: 4

whncode
whncode

Reputation: 429

I improved mpaf's solution, to get request directly from tag.

@register.simple_tag(takes_context = True)
def url_replace(context, field, value):
    dict_ = context['request'].GET.copy()
    dict_[field] = value
    return dict_.urlencode()

Upvotes: 10

mpaf
mpaf

Reputation: 6797

I did this simple tag which doesn't require any extra libraries:

@register.simple_tag
def url_replace(request, field, value):

    dict_ = request.GET.copy()

    dict_[field] = value

    return dict_.urlencode()

Use as:

<a href="?{% url_replace request 'param' value %}">

It wil add 'param' to your url GET string if it's not there, or replace it with the new value if it's already there.

You also need the RequestContext request instance to be provided to your template from your view. More info here:

http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/

Upvotes: 26

akaihola
akaihola

Reputation: 26845

In addition to the snippets mentioned by Mark Lavin, Here's a list of other implementations I could find for a Django template tag which modifies the current HTTP GET query string.

On djangosnippets.org:

On PyPI:

On GitHub:

Upvotes: 0

Mark Lavin
Mark Lavin

Reputation: 25164

There are a number of template tags for modifying the query string djangosnippets.org:

http://djangosnippets.org/snippets/553/
http://djangosnippets.org/snippets/826/
http://djangosnippets.org/snippets/1243/

I would say those are the most promising looking. One point in all of them is that you must be using django.core.context_processors.request in your TEMPLATE_CONTEXT_PROCESSORS.

Upvotes: 1

Igor
Igor

Reputation: 479

You can try https://github.com/dcramer/django-paging

Upvotes: 0

Related Questions