Callum
Callum

Reputation: 321

How do I use HTMX with Django class based views?

I'm fairly new to htmx and django. I can implement htmx through function-based views OK, as I just call the function and return a partial.html file into the page.

However I don't understand how to make it work with class-based views I'm now using in Django.

I'd like to load comments on a blog post when a user clicks the Load comments button. My thought is that I'd need to use htmx to do a swap or insertion into a point on my page where I want the comments loaded.

Here is my DetailView where I load the detail of an individual post.

class PostDetailView(DetailView):
    model = Post
    template_name = "post_detail.html"

    def get(self, request, **kwargs):
        print("method is being called")
        return render(request, "partial.html")

Here is my partial.html file that I'd like to be loaded into the page once the button on my post_detail.html page is clicked:

<h2 class="mt-2 mb-2">Comments:</h2>
{% if post.comments.all %}
    {% for comment in post.comments.all %}
        <div class="relative grid grid-cols-1 gap-4 p-4 mb-8 border rounded-lg bg-white shadow-lg">
            <div class="relative flex gap-4">
                <div class="flex flex-col w-full">
                    <div class="flex flex-row justify-between">
                        <p class="relative text-xl whitespace-nowrap truncate overflow-hidden">{{ comment.commenter }}</p>
                        <a class="text-gray-500 text-xl" href="#"><i class="fa-solid fa-trash"></i></a>
                    </div>
                    <p class="text-gray-400 text-sm">{{ comment.date_added }}</p>
                </div>
            </div>
            <p class="-mt-4 text-gray-500">{{ comment.body }}</p>
        </div>
    {% endfor %}
    {% else %}
        <p>No comments</p>
{% endif %}

And here's the button in my post_detail.html page which I'm trying to use to send a get or post (I've tried both) request to my post_detail url/view.

                            <button hx-get="{% url 'posts:post_detail' %}" hx-target="#here">Press</button>
                    </div>
                <div id="here">Swap this text out</div>

Finally, here's my urls.py file:

app_name = "posts"
urlpatterns = [
    path("create/", CreatePostView.as_view(), name="create_post"),
    path("home/", HomeView.as_view(), name="home"),
    path("post/<int:pk>", PostDetailView.as_view(), name="post_detail"),
    path("edit/<int:pk>", EditPostView.as_view(), name="edit_post"),
]

My understanding was that I needed to use htmx to send a get or post request to my class based view PostDetailView which would call the get() or post()method and return my partial.html into the hx-target div with the id of "here".

Where am I going wrong?

Upvotes: 5

Views: 3055

Answers (1)

V S
V S

Reputation: 130

In your View, you need to render the base template instead on first load i.e. normal get request. But htmx get requests triggered from the button click should render the partial instead.

Requests triggered using htmx have a hx-request header appended to them, so it is possible to identify the source.

class PostDetailView(DetailView):
    model = Post
    template_name = "post_detail.html"

    def get(self, request, **kwargs):
        print("method is being called")
        is_htmx = request.headers.get('HX-Request') == True
        if is_htmx:
            return render(request, "partial.html")

        return render(request, self.template_name)

Upvotes: 7

Related Questions