Comment (by spookylukey):
I think this whole area is solved by django-spurl -
https://github.com/j4mie/django-spurl
It builds on urlobject which can be used for Python code:
https://github.com/zacharyvoase/urlobject/
There is also furl for Python code: https://github.com/gruns/furl
I don't think we need to duplicate any of these within Django. Having a
template tag to do 1/10 of what spurl does is just an invitation to
include more and more of spurl's functionality. It might be useful to
have some links to spurl in the documentation.
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:25>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Comment (by funkybob):
Personally I think it wouldn't hurt to have a helper for the specific case
of altering the page number _only_.
In a prior project we ended up needing 4 different querystring
manipulators [and I'm sure there could have been more].
One would output the original, less any listed keys, plus any specified
keys _overridden_ in value.
One would just add new values.
One would return the original with only the listed keys.
A final just updated the page number.
This still doesn't cover, for instance, when you want to add a second
value to an existing key... or.... well, given it's a multi-dict, the
options are endless.
So, to reiterate: A _simple_ helper for helping with pagination, which is
a problem almost everyone encounters, would be good.
A general purpose querystring manipulator? Leave that to 3rd parties.
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:26>
Comment (by Jimmy Merrild Krag):
It's been some time since something happened on this one. i have just
stumpled into needing to change query strings in templates, so I thought
I'd add my findings.
I have created two rather simple filter which allows you ro edit the query
string. `django-spurl` already does some of this, however not very
elegantly. I think the following three filters would be a great addition
to Django that will get you "there" much of the time:
{{{
#!python
import six
from django import template
import collections
from django.http import QueryDict
register = template.Library()
@register.simple_tag
def build_query(**kwargs):
"""Build a query string"""
query_dict = QueryDict(mutable=True)
for k, v in kwargs.items():
if isinstance(v, collections.Iterable) and not isinstance(v,
six.string_types):
query_dict.setlist(k, v)
else:
query_dict[k] = v
return query_dict.urlencode()
@register.simple_tag(takes_context=True)
def set_query_values(context, **kwargs):
"""Override existing parameters in the current query string"""
query_dict = context.request.GET.copy()
for k, v in kwargs.items():
if isinstance(v, collections.Iterable) and not isinstance(v,
six.string_types):
query_dict.setlist(k, v)
else:
query_dict[k] = v
return query_dict.urlencode()
@register.simple_tag(takes_context=True)
def append_query_values(context, **kwargs):
"""Append to existing parameters in the current query string"""
query_dict = context.request.GET.copy()
for k, v in kwargs.items():
if isinstance(v, collections.Iterable) and not isinstance(v,
six.string_types):
for v_item in v:
query_dict.appendlist(k, v_item)
else:
query_dict.appendlist(k, v)
return query_dict.urlencode()
}}}
Usage is e.g. `<a href="?{% set_query_values page=page.next_page_number
%}">»</a>` or `<a href="?{% append_query_values selected=item.id
%}">Select {{ item.name }}</a>`
Note: They all support iterables as values.
I think the only ones probably missing is one for removing a key and one
for removing a specific value from a key.
I'm also thinking of merging the `set` and `append` (also adding `remove`)
by prepending each key with the action and letting `None` clear the list
when using `set_`. I imagine something like `{% modify_query set_level=7
set_nextlevel=None append_consumedlevels=processed_levels_list
remove_availablelevels=7 %}`.
What do you think? Any thoughts?
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:27>
Comment (by Jimmy Merrild Krag):
I made an implementation of the above mentioned `modify_query`.
[https://pastebin.com/SiDLqs4B]
Thoughts and comments are most welcome.
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:28>
* cc: Ning (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:29>
* cc: Thomas Capricelli (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:30>
Comment (by Federico Jaramillo Martínez):
Is this ticket still valid?
Would a PR with a templatetag be accepted?
If so, I could be working on this.
If anyone can confirm I would appreciate.
Thanks
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:31>
Comment (by Claude Paroz):
Sure, it's still valid. Read attentively the existing comments.
Maybe the greatest challenge of this ticket is to find a compromise
between functionality and simplicity, addressing the more common use cases
while accepting it won't address all possible needs.
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:32>
* cc: Carsten Fuchs (added)
Comment:
I too had reinvented this wheel a couple of years ago, unaware of this
ticket. Other implementations above are more powerful, but this one is
short:
{{{
#!python
@register.simple_tag
def query_string(*args, **kwargs):
"""
Combines dictionaries of query parameters and individual query
parameters
and builds an encoded URL query string from the result.
"""
query_dict = QueryDict(mutable=True)
for a in args:
query_dict.update(a)
remove_keys = []
for k, v in kwargs.items():
if v is None:
remove_keys.append(k)
elif isinstance(v, list):
query_dict.setlist(k, v)
else:
query_dict[k] = v
for k in remove_keys:
if k in query_dict:
del query_dict[k]
qs = query_dict.urlencode()
if not qs:
return ""
return "?" + qs
}}}
It cannot do everything, but covers all my use cases: Keep most of the
existing source parameters, but delete, add or change some. Examples:
{{{
{# Just repeat the parameters: #}
{% query_string request.GET %}
{# Add a parameter: #}
{% query_string request.GET format='pdf' %}
{# Change a parameter: #}
{% query_string request.GET page=next_page_number %}
{# Overwrite month and year with precomputed values, e.g. with
next_month_year = {'month': 1, 'year': 2022}, and clear the day: #}
{% query_string request.GET next_month_year day=None %}
}}}
I'm aware that posting yet another implementation does not achieve true
progress and that the more elaborate implementations above may be more
appropriate for inclusion in Django.
Still, I wanted to mention this because in my opinion it keeps the balance
between features and simplicity.
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:33>
Comment (by Leonardo Cavallucci):
I would really love to have this: I could work on this, if it is decided
how this should work
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:34>
* owner: (none) => Tom Carrick
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:35>
* has_patch: 0 => 1
Comment:
[https://github.com/django/django/pull/17368 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:36>
* needs_better_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:37>
* needs_better_patch: 1 => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:38>
* needs_better_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:39>
* needs_better_patch: 1 => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:40>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:41>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"e67d3580edbee1a4b58d40875293714ac3fc6937" e67d3580]:
{{{
#!CommitTicketReference repository=""
revision="e67d3580edbee1a4b58d40875293714ac3fc6937"
Fixed #10941 -- Added {% query_string %} template tag.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/10941#comment:42>