Problème de pagination avec htmx
Bonjour j'essaie de créer un système de pagination avec htmx, mais j'ai quelques soucis.
Voila la ma vue :
def post_list_view(request, tag_slug=None, category_slug=None):
"""Display the list of all published post"""
post_list = Post.published.all()
tag = None
category = None
categories = Category.objects.all()
if tag_slug:
tag = get_object_or_404(Tag, slug=tag_slug)
post_list = post_list.filter(tags__in=[tag])
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
post_list = post_list.filter(category=category)
paginator = Paginator(post_list, 3)
page_number = request.GET.get("page", 1)
try:
posts = paginator.page(page_number)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
except PageNotAnInteger:
posts = paginator.page(1)
context = {"posts": posts, "tag": tag, "category": category, "categories": categories}
if request.htmx:
return render(request, "blog/list-elements.html", context=context)
return render(request, "blog/list.html", context=context)
J'utilise django-htmx.
Et voila mon template :
{% load blog_tags %}
{% for post in posts %}
<a class="text-decoration-none" href="{{ post.get_absolute_url }}">
{% if forloop.last %}
<div class="card border-0 pb-3 pb-sm-5" hx-get="?page={{ page.next_page_number }}" hx-swap="afterend" hx-trigger="revealed">
{% else %}
<div class="card border-0 pb-3 pb-sm-5">
{% endif %}
<div class="row">
<div class="col-8">
<div class="card-body p-0">
<div class="pb-2 text-body mt-3 infscroll-author">{{ post.author }}</div>
<h1 class="mb-1 text-body fw-bold infscroll-title">{{ post.title }}</h1>
<h2 class="text-muted fs-6 d-none d-md-block">{{ post.body|markdown|truncatewords_html:30 }}</h2>
<div class="text-muted infscroll-date">{{ post.publish|date:"M d" }}</div>
<div class="text-muted">
{% for tag in post.tags.all %}
<a class="text-decoration-none text-muted" href="{% url 'blog:post_list_by_tag' tag.slug %}">
<span>{{ tag.name }}</span>
</a>
{% if not forloop.last %}, {% endif %}
{% endfor %}
</div>
</div>
</div>
<div class="col-4">
<img alt="" class="img-fluid float-end" src="https://picsum.photos/200/115"/>
</div>
</div>
</div>
</div></a>
{% endfor %}
Le problème étant le suivant lorsque je scroll vers le bas, j'ai bien de nouveaux post qui s'affiche seulement c'est tojours les mêmes qui s'affichent (comme on peut le voir su l'image) 
ça commence par le post 8, puis 7, puis 6 et hop on revient à 8, 7, 6 et ça jusqu'à l'infinie. En fait htmx charge toujours la même page et je ne comprends pas pourquoi. Lorsque je regarde le log de django dans la requête http je trouve ça :
> 2023-04-09 17:16:38 [09/Apr/2023 15:16:38] "GET /blog/?page= HTTP/1.1" 200 3691
Il n'y a rien après page=. Il semble qu'htmx ne comprenne pas ce qu'il y a dans la variable {{ page.next_page_number }}. Pourtant avant de passer à htmx j'utilisais un système de pagination classique et je n'avais pas de soucis de ce point de vue là.
Salut Flavien,
Je pense que le problème vient du fait que tu ne passes pas la page à ton contexte :
context = {"posts": posts, "tag": tag, "category": category, "categories": categories} # Pas de clé "page"
if request.htmx:
return render(request, "blog/list-elements.html", context=context)
Mais dans ce cas pourquoi sans utiliser htmx ça fonctionne ? Avant que j'utilise htmx, mon système de pagination fonctionnait très bien.La seule chose que j'ai modifié de ma précédente vue c'est en rajoutant cette ligne :
if request.htmx:
return render(request, "blog/list-elements.html", context=context)
Tout le reste est identique.
Tu passes le numéro de la page dans l'URL directement (et tu le récupère dans la vue avec page_number = request.GET.get("page", 1)).
Dans ton template HTML, avant d'utiliser HTMX, tu utilisais des boutons pour aller d'une page à l'autre j'imagine ?
Avec ou sans HTMX, là le problème c'est vraiment que tu ne passes nul part page au contexte, du coup dans ton template c'est normal que l'URL soit :
hx-get="?page=" (vu que {{ page.next_page_number }} ne retourne rien du coup).
Que contiennent tes templates list-elements.html et list.html ? (tu as un dépôt github ?)
Je crois que je commence à comprendre, effectivement avant j'avais cette ligne dans mon template :
{% include "blog/pagination.html" with page=posts %}
Je pense que c'est à ce moment là que je passe page au context.
Le lien de mon dépot : https://gitlab.com/django-web2/django-blog.git
J'imagine que maintenant avec htmx, je dois passer le mot clé page dans mon context dans ma fonction de vue car je n'utilise plus le template pagination.html ?
Oui c'est exactement ça !
Tu définissais posts égal à ton Paginator, et dans ton template du coup page représentait ton Paginator et tu pouvais donc faire next_page_number dessus.
Et là dans ton contexte tu définis "posts": posts, tu pourrais changer pour page et ton template HTMX aurait bien ton Paginator dans la variable de template page :
👇
context = {"page": posts, "tag": tag, "category": category, "categories": categories}
if request.htmx:
return render(request, "blog/list-elements.html", context=context)
Hum ok je viens de tester à l'instant, mais quand je fais ce que tu me dis comme je craignais je n'ai plus du tout de d'articles qui s'affichent.
J'ai donc opté pour cette solution qui je t'avoue n'es pas très élégante si tu as une meilleur idée je suis preneur.
context = {"posts": posts, "page": posts, "tag": tag, "category": category, "categories": categories}
if request.htmx:
return render(request, "blog/list-elements.html", context=context)
Salut Flavien !
En fait c'est juste un problème de nomenclature, il y a trop d'éléments qui s'appellent posts.
Pourquoi est-ce que tu assigne ton paginator à la variable posts ?
posts = paginator.page(page_number)
Ça me semble confu à partir de là, si c'est un paginator, appelle la variable paginator, là vu que tu l'appelles posts, c'est confus avec la liste de tes postes et ça doit créer des problèmes.
Inscris-toi
(c'est gratuit !)
Tu dois créer un compte pour participer aux discussions.
Créer un compte