Introduction
In this article I will show you, how to implement loading of additional content, via more button. Using django, REST API, htmx and daisyUI. I also assume that you, my dear, have already created a virtual environment for the django project, installed and configured rest-api and generally have a project ready for development. There will be no settings or presets in this article, let's get straight to the point. I will demonstrate everything on my new site, it's about history.
Frontend part
First, we need a page to place the loading button and templates to render the loading content. For example, I have a home page, I need to insert the following template code inside it:
It doesn't really matter what you wrap the included template in. I'm going to load articles and I want them all to be in a column, but not too wide. The important thing is to pass the articles variable to the included template parts/article-simple-paginator.html. Where to get it, the variable, see in the next chapter, now we'll look at other components of our templates.
Source code of parts/article-simple-paginator.html:
This code snippet is a flex box in a column direction, for article cards, and the actual download button at the very end. When we connect the template for rendering article cards, we also do not want to forget to send the articles variable there.
After (highlighted in yellow) comes the logic for displaying the content download button. If is_not_init is false, that is, if this is my first visit to the page. Then using the django tag, with, I manually create a link that the button will then use to send a request to the server.
But if this is not the first visit and is_not_init is true, then using the rest_api paginator, I get and send a link to the next page. And if the variable next is not defined, that is, we are at the end and there is nothing more to load, we do not render this button.
Now, actually, about the download button itself, the parts/more-button.html template:
Let's go through the attributes, in descending order:
- id - the usual ID of the button, you will need it so that you can find it later
- class - using classes from daisyUI, we style the button
- hx-get - where we send the request
- hx-target - where we insert the response from the server
- hx-indicator - an indicator to display while the content is loading
- hx-swap - how we insert the content, relative to hx-target. outerHTML means inserting the loaded content into the parent element of the DOM tree, while preserving the button itself.
The .htmx-indicator class is an indicator with default styles. Actually, we indicate that this is our indicator.
You can also consider the parts/article-cards.html template, but this does not make much sense, because it already depends on what exactly you want to display. In my case, these are articles, but in yours it can be anything. But in any case, it must be a collection of something. And here is the code:
And this is how it looks on the site itself:

I haven't completely styled the site yet, but it's not bad, I think.
Backend part
Now about the backend. Let's start by writing a class-based view for the page where articles need to be loaded. In the file, views.py:
In general, the idea is this: you need to return a collection of articles and a pagination page number with a GET request. You don’t have to write all this if you don’t need content with the first request, that is, you don’t mind an empty page initially.
That’s all, although it’s also worth noting how and how many elements I return. I filter them by language (not necessarily if the site is monolingual). I sort them by publication date (the newest ones come first). And finally, I return exactly as many as defined in the StandartPagination class.
Now, let’s write a serializer for the model that needs to be loaded. This is for working with the REST API. And, since I have articles, this serializer looks like this, in the Backend/serializers.py file:
Yes, I have so many fields for an article, a lot...
With a ready serializer and model for loading, you can write another class-based view, specifically for loading when the "More" button is pressed:
Here, we create a paginator, inheriting from the PageNumberPaginator class from the REST API. Where we specify the number of elements per page (page_size) and the total number of available elements (max_page_size).
The ArticlePaginatedModelView class will directly load the necessary articles, which we will do by inheriting from the ListAPIView mixin. A special class from the REST API, which is created to go through large collections of elements.
But, it needs to be configured in advance so that it works correctly:
- serializer_class - Specify the serializer that will be used to obtain raw data about the model
- renderer_classes - how we will return the result, if not specified, it will return a JSON file. We need a rendered piece of HTML, so we use TemplateHTMLRenderer
- template_name - in which template the collection of loaded elements will be rendered
- pagination_class - how we will go through the collection of elements
- queryset - which elements will be loaded
And to return, specifically the collection, it is necessary to override the list method. Where we filter our collection by language (optional). You can just use get_queryset() method.
Next, we get a piece of the necessary elements for loading and a link to the next page. And to indicate that this request is not the first, we define the variable is_not_init = True here.
Everything is ready, all that remains is to connect these views to Backend/urls.py:
Conclusion
This code should be enough to write a simple button to load content from the server, using only Django as a base, a little REST API and even less HTMx code.