Django, HTMX, общие представления на основе классов, наборы запросов и разбивка на страницы

Я думаю, что это в равной степени вопрос минимализма и эффективности, но в любом случае...

У меня есть общий ListView, который я использую, а также HTMX, которым я пользуюсь впервые, но пока мне это нравится! Тем не менее, у меня есть некоторые странности с поведением по умолчанию в представлении на основе универсального класса, с которыми я не уверен, как справиться. Учитывая следующее...

class AccountListView(ListView):
    model = Account
    template_name = 'account_list.html'
    paginate_by = 100

    def get_queryset(self):
        query = self.request.POST.get('query')
        try:
            query = int(query)
        except:
            pass
        if query:
            if isinstance(query, int):
                return Account.objects.filter(
                    Q(id=query)
                )
            else:
                return Account.objects.filter(
                    Q(full_name__icontains=query) | Q(email1=query) | Q(email2=query) | Q(email3=query)
                ).order_by('-date_created', '-id')

        return Account.objects.all().order_by('-date_created', '-id')

    def post(self, request, *args, **kwargs):
        response = super().get(self, request, *args, **kwargs)
        context = response.context_data
        is_htmx = request.headers.get('HX-Request') == 'true'
        if is_htmx:
            return render(request, self.template_name + '#account_list', context)

        return response

    def get(self, request, *args, **kwargs):
        response = super().get(self, request, *args, **kwargs)
        context = response.context_data
        is_htmx = request.headers.get('HX-Request') == 'true'
        if is_htmx:
            return render(request, self.template_name + '#account_list', context)

        return response

Как вы, вероятно, можете догадаться, моя проблема заключается в том, что я пытаюсь реализовать две разные функции в одном общем представлении ...

  1. быстрый поиск, который проверяет, ввел ли пользователь целое число (и если да, то выполняет поиск по идентификатору учетной записи), или если это не целое число, также позволяет пользователю искать полное имя или адрес электронной почты.
  2. кроме того, я использую частичные элементы шаблона, чтобы обеспечить бесконечную прокрутку самого представления списка, проверяя, присутствует ли HTMX в запросе

Часть с бесконечной прокруткой работает нормально, но что больше не работает нормально после добавления HTMX в микс, так это мой быстрый поиск. Я могу предположить, что это связано с тем, что URL-адрес self меняется незаметно, и в какой-то момент я попадаю в разбивку запросов на страницы вместо полного набора запросов...

  File "C:\Users\xxxxxx xxxxxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\django\template\base.py", line 977, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "C:\Users\xxxxxx xxxxxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\django\template\base.py", line 1075, in render
    output = self.filter_expression.resolve(context)
  File "C:\Users\xxxxxx xxxxxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\django\template\base.py", line 722, in resolve
    obj = self.var.resolve(context)
  File "C:\Users\xxxxxx xxxxxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\django\template\base.py", line 854, in resolve
    value = self._resolve_lookup(context)
  File "C:\Users\xxxxxx xxxxxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\django\template\base.py", line 925, in _resolve_lookup
    current = current()
  File "C:\Users\xxxxxx xxxxxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\django\core\paginator.py", line 215, in next_page_number
    return self.paginator.validate_number(self.number + 1)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "C:\Users\xxxxxx xxxxxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\django\core\paginator.py", line 71, in validate_number
    raise EmptyPage(self.error_messages["no_results"])
django.core.paginator.EmptyPage: That page contains no results
[24/Jul/2025 02:18:56] "POST /search HTTP/1.1" 500 177746

Итак, вопрос в том, каков наиболее эффективный способ обработки подобных catch22, когда Django и HTMX живут бок о бок друг с другом в общих представлениях?

Решено, нужно проверить, разбит ли вводимый частичный шаблон на страницы или нет, django корректно применяет is_paginated = False к методу post по умолчанию в общем представлении....

-> import pdb;pdb.set_trace()
(Pdb) context
{'paginator': <django.core.paginator.Paginator object at 0x000001AE88947750>,
 'page_obj': <Page 1 of 1>, 'is_paginated': False, 'object_list': <QuerySet [<Account: XYZ Company>]>, 'account_list': <QuerySet [<Account: XYZ Company>]>, 'view': <accounts.views.AccountListView object at 0x000001AE88947610>}

Таким образом, добавление этого в логику шаблона для проверки и просмотра того, что мы делаем с результатами, исправляет это. Ранее моя условная проверка в шаблоне ограничивалась {% if forloop.last %}

{% startpartial account_list %}
{% for item in object_list %}
{% if forloop.last %}
<tr hx-get="accounts?page={{ page_obj.next_page_number }}"
  hx-trigger="revealed"
  hx-swap="afterend">
{% else %}
<tr>
{% endif %}
  <th scope="row">{{item.id}}</th>
  <td>{{ item.account_type }}</td>
  <td>{{ item.first_name }}</td>
  <td>{{ item.last_name }}</td>
  <td><a href="mailto:{{ item.email1 }}">{{ item.email1 }}</a></td>
  <td>{{ item.organization_name }}</td>
  <td><a href="tel:{{ item.mobile_phone }}">{{item.mobile_phone.as_national}}</a></td>
  <td>{{ item.date_created }}
</tr>
{% endfor %}
{% endpartial %}

Изменение этого параметра с учетом {% is paginated %} исправляет это, заставляя шаблон игнорировать вывод с разбивкой на страницы HTMX при возврате результатов поиска.

{% startpartial account_list %}
{% for item in object_list %}
{% if forloop.last and is_paginated %}
<tr hx-get="accounts?page={{ page_obj.next_page_number }}"
  hx-trigger="revealed"
  hx-swap="afterend">
{% else %}
<tr>
{% endif %}
  <th scope="row">{{item.id}}</th>
  <td>{{ item.account_type }}</td>
  <td>{{ item.first_name }}</td>
  <td>{{ item.last_name }}</td>
  <td><a href="mailto:{{ item.email1 }}">{{ item.email1 }}</a></td>
  <td>{{ item.organization_name }}</td>
  <td><a href="tel:{{ item.mobile_phone }}">{{item.mobile_phone.as_national}}</a></td>
  <td>{{ item.date_created }}
</tr>
{% endfor %}
{% endpartial %}
Вернуться на верх