Django & HTMX - после GET отображается только часть html-шаблона

Я хочу создать клон instagram. Я создал post.html, который включает файл post-card.html для всех постов и post-filter.html для фильтрации постов.

<!-- simple post.html view -->
<div>
  <div>
    {% include '_includes/bars/post-filter.html' %}
  </div>
  <div id="more-posts-wrapper">
    {% for post in posts %}
      {% include '_includes/cards/post-card.html' %}
    {% endfor %}
  </div>
</div>

Теперь я добавил htmx для загрузки дополнительных постов после нажатия load more button. Я попытался загрузить новые посты после существующих внутри div с помощью id=more-posts-wrapper:

<div>
  <div>
    {% include '_includes/bars/post-filter.html' %}
  </div>
  <div hx-get="?page={{ page_obj.next_page_number }}"
    hx-trigger="click"
    hx-swap="innerHTML"
    hx-target="#more-posts-wrapper">
      <p>LOAD MORE</p>
  </div>
  <div id="more-posts-wrapper">
    {% for post in posts %}
      {% include '_includes/cards/post-card.html' %}
    {% endfor %}
  </div>
</div>

К сожалению, если я нажимаю на кнопку, правильный ответный пост доставляется, но весь документ post.html загружается после div с id=more-posts-wrapper. Я хочу загрузить только файл post-card.html и не перезагружать файл post-filter.html.

Кто-нибудь знает, что я могу сделать?

В HTMX у нас есть два типа запросов:

  • Полная страница: когда пользователь загружает страницу, мы хотим показать полный шаблон с фильтрами и содержимым.
  • Частичная страница: после первой загрузки мы хотим загрузить только часть контента через HTMX и обновить соответствующую часть страницы.

Мы должны соответствующим образом структурировать наши шаблоны, чтобы мы могли повторно использовать их в этих двух запросах.

Шаблон полной страницы post_page.html:

<div>
  <div>
    {% include '_includes/bars/post-filter.html' %}
  </div>
  <div id="more-posts-wrapper">
    {% include 'posts_partial.html' %}
  </div>
</div>

И частичный шаблон posts_partial.html, куда мы помещаем все, что хотим загрузить через HTMX:

<div hx-get="?page={{ page_obj.next_page_number }}"
     hx-trigger="click"
     hx-swap="innerHTML"
     hx-push-url="true"
     hx-target="#more-posts-wrapper">
      <p>LOAD MORE</p>
</div>
<div id="more-posts-wrapper">
  {% for post in posts %}
    {% include '_includes/cards/post-card.html' %}
  {% endfor %}
</div>

В этом шаблоне у нас есть почтовые карточки для выбранной страницы, кроме того, мы должны разместить здесь нашу кнопку 'Load more', потому что мы должны обновлять значение page_obj.next_page_number после каждого запроса на кнопку.

В функции view мы можем проверить наличие заголовка HX-Request: true, чтобы определить HTMX-запрос. Если запрос был сделан HTMX, мы устанавливаем частичный шаблон в методе get_template_names(), в противном случае мы используем полный шаблон страницы.

class MemesView(ListView):
    model = Post
    context_object_name = 'posts'
    paginate_by = 1
    
    def get_template_names(self):
        is_htmx = self.request.headers.get('HX-Request') == 'true'
        return 'posts_partial.html' if is_htmx else 'post_page.html'

Кроме того, я добавил hx-push-url="true", чтобы HTMX обновил номер страницы в URL, чтобы пользователь мог обновить и получить правильную страницу после нескольких запросов HTMX.

Вернуться на верх