How to update a page without Javascript

How to use Htmx in Django

By Omid Estaji, October 16, 2022
 #Django

There are some methods for updating whole or usually a part of a web page using Javascript, Ajax or jQuery. Is there any alternative way to update a part of a web page? Answer is yes! We can do it using Htmx.

Htmx is a useful method to build modern user interfaces with the simplicity and power of hypertext. Not only updates a part of a page but Htmx also can do some other useful things. If you are looking for a Javascript alternative in some cases look at htmx docs.

How to use Htmx in Django

We will update a part of a page using Htmx in this exmaple. You can find this method in Htmx's docs as polling.

overview

template ---- page.html
         ---- refresh.html

views.py ---- PageView
         ---- RefreshView

urls.py ----- path for page.html/PageView
        ----- path for refresh.html/RefreshView

Add Htmx to django project

The fastest way to get going with htmx is to load it via a CDN. Add this script to each template we want or base.html template.

page.html :

...
{% block footer_script %}
    <script src="https://unpkg.com/htmx.org@1.8.0"></script>
{% endblock footer_script %}
...

Add Htmx to templates

Create a <div></div> to hold part of the page which we want updating it using Htmx automatically without refreshing whole page.

page.html :

...
<div hx-get="/refresh" hx-trigger="every 3s">
  <table class="table table-striped">
    <thead>
      <tr>
        <th scope="col">#</th>
        <th scope="col">Name</th>
        <th scope="col">Code</th>
      </tr>
    </thead>
    <tbody>
    </tbody>
  </table>
</div>
...

In page.html we defined "evey 3 s" in hx-trigger as interval time. Client's browser will send a get request to /refresh url every 3 seconds.

Then write Html and Django codes which we want replaced in the defined <div></div> periodically.

refresh.html :

<table class="table table-striped">
  <thead>
    <tr>
    <th scope="col">#</th>
    <th scope="col">Name</th>
    <th scope="col">Code</th>
    </tr>
  </thead>
  <tbody>
    {% for i in prisoners %}
      <tr>
        <th scope="row">{{ forloop.counter }}</th>
        <td>{{ i.name }}</td>
        <td>{{ i.code }}</td>
      </tr>
    {% endfor %}
  </tbody>
</table>

We created an empty table in page.html then update it every 3 seconds using refresh.html with new records.

Update urls.py for Htmx

Create 2 different urls for page.html and refresh.html.

urls.py:

...
from .views import PageView, RefreshView
...
urlpatterns = [
...
path("page", PageView.as_view(), name="page"),
path("refresh", RefreshView.as_view(), name="refresh-page"),
]
...

How to stop Htmx polling in Django

Htmx sends get request to refresh url every 3 seconds in our example as interval time. It will send a get request from client's browser periodically, We can see it in inspect mode of our browser in network tab. Docs says:

If you want to stop polling from a server response you can respond with the HTTP response code 286 and the element will cancel the polling.

views.py :

...
class PageView(TemplateView):
    """View for result page which updates using htmx"""
    template_name = "page.html"

    #use your get function here.
    ...

class RefreshView(TemplateView):
    """View for returning new results based on htmx"""
    template_name = "refresh.html"

    def get(self, request, *args, **kwargs):
        #your view logic here
        ...
        if progress == 100: #stop htmx
            return self.render_to_response(context, status=286)
        else:
            return self.render_to_response(context, status=200)

Client's browser sends get to RefreshView periodically untill server responses with a 286 status code which means stop!