Skip to content

refactor(forms): replace custom querystring logic with Django {% querystring %} tag#19672

Open
Deign86 wants to merge 2 commits into
WeblateOrg:mainfrom
Deign86:refactor/querystring-template-tag
Open

refactor(forms): replace custom querystring logic with Django {% querystring %} tag#19672
Deign86 wants to merge 2 commits into
WeblateOrg:mainfrom
Deign86:refactor/querystring-template-tag

Conversation

@Deign86
Copy link
Copy Markdown

@Deign86 Deign86 commented May 20, 2026

Replaces the manual querystring building in SearchForm.items(), urlencode(), and reset_offset() (and ChangesForm equivalents) with Django's built-in {% querystring %} template tag introduced in Django 5.1.

Changes

Python

  • Removed SearchForm.items(), SearchForm.urlencode(), SearchForm.reset_offset() (weblate/trans/forms.py)
  • Removed ChangesForm.items(), ChangesForm.urlencode() (weblate/trans/forms.py)
  • Removed unused from django.utils.http import urlencode import
  • Updated search() view in search.py to stop passing query_string/ search_url/ search_items to templates
  • Updated ChangesView in changes.py: replaced self.changes_form.urlencode() with self.request.GET.urlencode()
  • Updated edit.py views: removed search_url, search_items, reset_offset() references

Templates

  • Updated paginator.html: pagination links now use {% querystring page=X limit=Y %}
  • Updated change_list.html: all ?{{ query_string }}?{% querystring %}
  • Updated translate.html, zen.html, zen-units.html: {{ search_url }}{% querystring %}
  • Updated embed-units.html, last-changes-content.html: same pattern

This simplifies the codebase by removing ~140 lines of manual querystring manipulation in favor of Django's built-in solution.

Closes #13638

Copilot AI review requested due to automatic review settings May 20, 2026 19:06
@Deign86 Deign86 requested a review from nijel as a code owner May 20, 2026 19:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (2)

weblate/templates/paginator.html:45

  • The paginator “jump to position” GET form no longer includes hidden inputs for the active filters/search parameters (previously provided via search_items). Submitting the position form will now drop all existing query params except page/limit, changing the result set unexpectedly. Preserve the current query parameters in the form submission (e.g., render hidden inputs from request.GET excluding page/limit, or use a querystring-based action that retains them).
      <a class="position-input-editable" title="{% translate "Go to position" %}">
        {# djlint:off #}
        {% if not paginator_form %}<form method="get"{% if anchor %} action="#{{ anchor }}"{% endif %}>{% endif %}
        {# djlint:on #}
        <input {% if paginator_form %}form="{{ paginator_form }}"{% endif %}
               type="hidden"
               name="limit"
               value="{{ page_obj.paginator.per_page }}"
               aria-label="{{ page_obj.paginator.per_page }}" />

weblate/templates/trans/change_list.html:51

  • change_list.html now ends inside {% block content %} without closing {% if form.is_valid %}, without rendering the search <form method="get">…</form>, and without {% endblock content %}. This is a template syntax error and will break the changes page rendering. Restore the missing closing tags/content (or adjust the structure) so the template is complete.
{% block content %}
  {% if form.is_valid %}
    {% include "paginator.html" %}
    {% format_last_changes_content last_changes=object_list user=user %}


# Some URLs we will most likely use
base_unit_url = f"{obj.get_translate_url()}?{search_result['url']}&offset="
base_unit_url = f"{obj.get_translate_url()}?{request.GET.urlencode()}&offset="

# Some URLs we will most likely use
base_unit_url = f"{obj.get_translate_url()}?{search_result['url']}&offset="
base_unit_url = f"{obj.get_translate_url()}?{request.GET.urlencode()}&offset="
)

base_unit_url = f"{reverse('browse', kwargs={'path': obj.get_url_path()})}?{search_result['url']}&offset="
base_unit_url = f"{reverse('browse', kwargs={'path': obj.get_url_path()})}?{request.GET.urlencode()}&offset="
Comment on lines 781 to 785
initial={"scope": "global" if unit.is_source else "translation"},
),
"context_form": ContextForm(instance=unit.source_unit, user=user),
"search_form": search_result["form"].reset_offset(),
"search_form": search_result["form"],
"secondary": secondary,
</li>
<li class="page-item{% if page_obj.paginator.num_pages == page_obj.number %} disabled{% endif %}">
<a href="?page={{ page_obj.paginator.num_pages }}&amp;limit={{ page_obj.paginator.per_page }}{% if page_obj.paginator.sort_by %}&amp;sort_by={{ page_obj.paginator.sort_by }}{% endif %}{% if query_string %}&amp;{{ query_string }}{% endif %}{% if anchor %}#{{ anchor }}{% endif %}"
<a href="?{% querystring page=page_obj.paginator.num_pages limit=page_obj.paginator.per_page %}{% if page_obj.paginator.sort_by %}&amp;sort_by={{ page_obj.paginator.sort_by }}{% endif %}{% if anchor %}#{{ anchor }}{% endif %}"
Comment on lines 95 to 99
<td>
{% if unit.context %}
<a href="{{ unit.get_absolute_url }}{% if include_search and search_url %}&amp;{{ search_url }}{% elif sort_query %}&amp;sort_by={{ sort_query }}{% endif %}">
<a href="{{ unit.get_absolute_url }}{% if include_search %}{% querystring %}{% elif sort_query %}&amp;sort_by={{ sort_query }}{% endif %}">
{% format_source_string unit.context unit wrap=True search_match=search_query %}
</a>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Utilize {% querystring %} template tag

2 participants