Enhancement Proposal for querystring template tag: Support for dynamic context-based keys

Problem Statement

Currently, the {% querystring %} template tag treats the keys in kwargs as static strings. While this works for simple use cases, it severely limits the reusability of templates in component-based architectures.

When using {% include %} to render a reusable component (like a generic filter, a sortable table header, or a pagination widget), the parameter name (the key) often needs to be dynamic, just like the value.

The Use Case

Imagine a reusable include for a sortable column: sort_link.html

<a href="{% querystring sort_param=field_name %}">
    Sort by {{ field_label }}
</a>

If we include it like this:

{% include 'sort_link.html' with sort_param='order_by' field_name='price' field_label='By Price' %}

Current Behaviour: It produces ?sort_param=price.
Expected/Desired Behaviour: It should produce ?order_by=price.

Proposed Solution

Add an optional boolean parameter resolve_keys (or similar) to the querystring tag. When set to True, the tag will look up the key names in the current context before processing the query dict.

Alternatively, there could be a dedicated template tag that reuses the current querystring

@register.simple_tag(takes_context=True)
def querystring(context, query_dict=None, resolve_keys=False, **kwargs):
    # ... existing logic ...
    
    for _key, value in kwargs.items():
        # Look up the key name in context if the flag is True
        key = context.get(_key) if resolve_keys else _key
        
        if key is None:
            # suggested behaviour - remove this key if in parameters, like if passed `key=None`
            
        # ... correct logic continues ...
       

Benefits

Decoupling: Templates don’t need to know the specific backend parameter names.
DRY: One include can handle different filtering/sorting logic across different views.
Consistency: Aligns with how Django handles dynamic values, extending that logic to keys.

The same is issued here: #36941 (Enhancement Proposal for querystring template tag: Support for dynamic context-based keys) – Django

I am sympathetic to the problem but I don’t think we can make this particular change because it’s backwards incompatible. The proposed dual-purpose syntax is also kinda unclear.

I think the easiest solution to your problem is to have a filter that creates a dictionary for a given key/value that’s passed through the context as a positional argument to querystring. That allows the flexibility of passing multiple different keys as well.

I appreciate the feedback regarding backward compatibility. However, I believe the suggested ‘filter’ workaround introduces unnecessary friction and complexity into the template layer.

Here is why a native/dedicated tag is a more robust approach:

  • Template Leanliness: Forcing a filter to construct a dictionary directly in the HTML violates the principle of keeping templates lean. It moves the construction logic from the tag—where it belongs—into the prose of the template, making it harder to read and maintain.

  • Component Encapsulation: When building reusable components, the goal is to keep the interface clean. Forcing the parent template to pre-process dictionary mappings for a child component’s internal link generation creates tight coupling.

  • A Step in the Right Direction: While I can (and often do) solve this by writing my own custom tags to bypass these limitations, the existence of the built-in {% querystring %} is a step in the right direction. It should be the ‘batteries-included’ solution. Having to maintain a library of custom tags for such a fundamental dynamic behavior feels like a missed opportunity for the core framework.

  • Complexity & DX: Using a filter to pass a positional argument to a tag feels like a ‘hacky’ redirection. It breaks the intuitive flow and forces a fragmented developer experience for a common modern use case.

  • Alignment with Modern Django: As Django moves towards better support for template partials, HTMX and component-based architectures, having a built-in way to handle dynamic keys directly aligns with the goal of simplifying templates.

If a dual-purpose syntax is too risky for backward compatibility, a dedicated tag (e.g., {% dynamic_querystring %}) would be a much cleaner, more ‘Django-way’ solution than requiring developers to inject dictionary-building logic into their templates.