Olivier Pons
Olivier Pons

Reputation: 15778

How to remove a GET parameter properly

I needed to remove a parameter from the GET url. I didn't find a "proper" way to do it, so I wrote my own filter like this:

@register.filter(name='url_without_parameter')
def url_without_parameter(arg1, arg2):
    """
    Removes an argument from the get URL.
    Use:
        {{ request|url_without_parameter:'page' }}

    Args:
        arg1: request
        arg2: parameter to remove
    """
    if arg1.GET.getlist(arg2):
        # get all parameters :
        full_url = urlparse.urlparse(arg1.get_full_path())
        parameters = {}
        # reconstruct query
        for key, value in urlparse.parse_qsl(full_url.query):
            if parameters.get(key, None) is None:
                parameters[key] = value
        # remove parameters
        if parameters.get(arg2) is not None:
            del parameters[arg2]
        arg1.META['QUERY_STRING'] = u'&'.join([
            u'{}={}'.format(key, value)
            for key, value in parameters.iteritems()])

    return arg1.get_full_path()

Then I'm using it like this:

{{ request|url_without_parameter:'page' }}

And the advanced way is:

href="{{ request|url_without_parameter:'page' }}&page={{ obj.page }}"

My problem is when there's not other parameters in the GET of the URL. This creates URLs like "/test&page=1" which is not good.

So I had to write another filter to make this work like that:

href="{{ request|url_without_parameter:'page' }}{{ request|url_get_separator }}page={{ obj.page }}"

With my url_get_separator filter.

@register.filter(name='url_get_separator')
def url_get_separator(arg1):
    """
    Returns '?' or '&' if there are QUERY parameters in the URL
    Use:
        {{ request|url_get_separator }}

    Args:
        arg1: request
    """
    return u'&' if arg1.META.get('QUERY_STRING', '') else u'?'

I find all of this pretty ugly and hard to read and hard to maintain. Do you know any other better way to simply replace a value of a GET in the URLs?

Upvotes: 0

Views: 3611

Answers (1)

Steve
Steve

Reputation: 5853

I use this tag mostly for pagination links within my project, i.e. to retain everything but switch the page number for the numerical hyperlinks, you'll notice I trash the _pjax param if it exists:

@simple_tag
def query_transform(request, **kwargs):
    """usages: {% query_transform request page=1 %}"""
    updated = request.GET.copy()

    for k, v in kwargs.iteritems():
        updated[k] = v

    # trash any pjax params, we never want to render those
    try:
        del updated['_pjax']
    except KeyError:
        pass

    return updated.urlencode()

I think maybe you want something similar, and maybe the trick you were missing was to call copy on the request.GET dictionary and mess with that, rather than the URL.

Upvotes: 1

Related Questions