Django 和 HTMX - 在 GET 之后仅显示 html 模板的部分

Django & HTMX - after GET show only section of html template

我想创建一个 Instagram 克隆。我创建了一个 post.html,其中包括一个用于所有 post 的 post-card.html 文件和一个用于过滤 [=38] 的 post-filter.html =]s.

<!-- 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 后加载更多 posts。我尝试在 div 中现有的 post 之后加载新的 posts 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,但是 整个 post.html 文档会在 [=36= 之后加载 ] 和 id=more-posts-wrapper。我只想加载 post-card.html 文件而不是重新加载 post-filter.html 文件。

我的views.py

class MemesView(ListView):
    model = Post
    template_name = 'memes.html'
    context_object_name = 'posts'
    paginate_by = 1

有人知道我能做什么吗?

对于 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>

在这个模板中,我们有所选页面的 post 卡片,此外我们还必须将 'Load more' 按钮放在这里,因为我们必须更新 page_obj.next_page_number 值在按钮的每个请求之后。

在视图函数中我们可以检查 HX-Request: true header in order to detect a HTMX request. If the request was made by HTMX, we set the partial template in the 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 请求后刷新并接收正确的页面。