How can I implement polling the table and keep the filter applied to it? [Django-filter] [HTMX]

I need to filter my database while live updating it too. However, the current rendering doubles the form and resets the filter to show all the data. How can I filter my data and update it at the same time

filters.py

import django_filters
from django_filters import DateFilter
from .models import CheckingStatus, Participant
from django.db.models import Q


class ParticipantFilter(django_filters.FilterSet):
    class Meta:
        model = Participant
        fields = '__all__'

views.py

def display_view(request):
    myFilter = ParticipantFilter(request.GET, queryset=Participant.objects.all())
    data = myFilter.qs
    return render(request, 'display.html', {'data': data, 'myFilter': myFilter})

HTML

  <body>
          <form method ="get">
            {{myFilter.form}}
            <button class "btn btn-primary" type = "Submit"></button>
        </form>
        <br><br>

    <div id="table-results" hx-get="/display" hx-trigger="every 2s">

     <table border="1" class="table table-dark table-hover">
         <thead>
             <th>First_name</th>
             <th>Last_name</th>
             <th>Age</th>
             <th>Checking Status</th>
             <th>Time</th>
             <th>Date</th>
         </thead>
         {% for k in data  %}
         <tr>
             <td>{{k.first_name}}</td>
             <td>{{k.last_name}}</td>
             <td>{{k.age}}</td>
             <td>{{k.checking.checking_status}}</td>
             <td>{{k.checking.time}}</td>
             <td>{{k.checking.date}}</td>
         
         </tr>
         
         {% endfor %}
     </table>
    </div>
  </body>

Thanks for your time

The reason the form is being doubled is because you’re rerendering the entire page using html, and the original form is outside the html div. You’ll want to create a “data only” view to only render that table for use by html.

To keep the filter, you’ll want to append the current filter to your hx-get attribute when you render that element and replace that element as part of the get. (hx-swap=“outerHTML”)

I am fairly new to Django and general programing so sorry for the novice questions

What HTML page would the data_only view render if any?

def data_only_view(request):
    data = Participant.objects.all()
    return render(request, 'display.html', {'data': data})

It’s not so much a “Django” thing as it is an “HTMX” thing.

You have:

This is going to call your view referenced by the /display url. That view is going to render some HTML and return it to HTMX. HTMX is going to use that HTML (by default) to replace the contents of that div, not the entire page.

So whatever view you want HTMX to call, should only render what you’re showing as the <table>...</table> portion of the page. This means it should most likely be a different view than what you’re using to render that page, and a different template as well.

Now, when your filter is submitted, it’s being submitted as a url query variable. This means that if you want the automatic refresh to keep using those filters, you want to initially render that page with adding that query variable to the url defined in the hx-get attribute. (Ignore my comment about hx-swap in my previous reply. Thinking about it some more, I don’t think you need to use it here. Your form submission is going to cause a full-page refresh.)

2 Likes

I believe I implemented what you stated
The database page does not render until I press submit and it does not filter
What should I be looking at?

{% load static %}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Display</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.rtl.min.css" integrity="sha384-WJUUqfoMmnfkBLne5uxXj+na/c7sesSJ32gI7GfCk4zO4GthUKhSEGyvQ839BC51" crossorigin="anonymous">
    <script src="https://unpkg.com/htmx.org@1.8.5" integrity="sha384-7aHh9lqPYGYZ7sTHvzP1t3BAfLhYSTy9ArHdP3Xsr9/3TlGurYgcPBoFmXX2TX/w" crossorigin="anonymous"></script>

  </head>
  <body>
    <form method ="get"  hx-get = '#table-results'>
      {{myFilter.form}}
      <button class "btn btn-primary" type = "Submit"></button>
  </form>
  <br><br>

<div id="table-results" hx-get="/database" hx-trigger="every 2s">
</div>
</body>

</html>

1 - The <form> portion of your original page should not be changed.

2 - Your original view and everything that it does, should not be changed.

3 - Your <div> with the hx-get only changes in that you want to render the url being referenced by the hx-get directive, with the query variable submitted by the form.

4 - You probably also want to render your original table in the full page template. (Note, you could include your “table template” in your page template to keep from having it duplicated.)

1 Like

I implemented what I understood from your post
When I render from the database.html it takes time to load, and disappears when I use the filter
the query variable don’t seem to be applied only in the fit request, but then resets to nothing

{% load static %}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Display</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.rtl.min.css" integrity="sha384-WJUUqfoMmnfkBLne5uxXj+na/c7sesSJ32gI7GfCk4zO4GthUKhSEGyvQ839BC51" crossorigin="anonymous">
    <script src="https://unpkg.com/htmx.org@1.8.5" integrity="sha384-7aHh9lqPYGYZ7sTHvzP1t3BAfLhYSTy9ArHdP3Xsr9/3TlGurYgcPBoFmXX2TX/w" crossorigin="anonymous"></script>

  </head>
  <body>
    <form method ="get">
      {{myFilter.form}}
      <button class "btn btn-primary" type = "Submit"></button>
  </form>
  <br><br>


  <table border="1" class="table table-dark table-hover">
    <thead>
      <th>First_name</th>
      <th>Last_name</th>
      <th>Age</th>
      <th>Checking Status</th>
      <th>Time</th>
      <th>Date</th>
  </thead>
    <div id="table-results" hx-get="/database" hx-trigger="every 2s">
    </div>
  </table>
</body>

</html>

database.html


    {% for i in data  %}
    <tr>
        <td>{{i.first_name}}</td>
        <td>{{i.last_name}}</td>
        <td>{{i.age}}</td>
        <td>{{i.checking.checking_status}}</td>
        <td>{{i.checking.time}}</td>
        <td>{{i.checking.date}}</td>
    
    </tr>
    
    {% endfor %}

May you explain in bullet points, it help a lot

You have essentially addressed the first two items in my previous post. You now need to handle #3 and #4.