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
Как вы, вероятно, можете догадаться, моя проблема заключается в том, что я пытаюсь реализовать две разные функции в одном общем представлении ...
- быстрый поиск, который проверяет, ввел ли пользователь целое число (и если да, то выполняет поиск по идентификатору учетной записи), или если это не целое число, также позволяет пользователю искать полное имя или адрес электронной почты.
- кроме того, я использую частичные элементы шаблона, чтобы обеспечить бесконечную прокрутку самого представления списка, проверяя, присутствует ли 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 %}