Résolue

Pagination avec double Queryset

# Affichage # Bases de données # Django

Gabriel Trouvé

Mentor

Bonsoir,

Première fois que j'utilise Paginator, et je commence direct avec un double queryset.

Mon code views :

def ideas_and_request_ideas_view(request):
    ideas = Idea.objects.filter(status=True, paid=False, request=False)
    request_ideas = Idea.objects.filter(status=True, paid=False, request=True)

    paginator = Paginator(ideas | request_ideas, 1)
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    if request.method == "GET":
        search = request.GET.get("search")
        if search:
            ideas = Idea.objects.filter(name__icontains=search, status=True, paid=False, request=False)
            request_ideas = Idea.objects.filter(name__icontains=search, status=True, paid=False, request=True)

    return render(request, "ideas/all.html", context={'ideas': ideas,
                                                      'request_ideas': request_ideas,
                                                      'page_obj': page_obj})

Ensuite le template (je ne mets que la partie paginator) :

<div class="row">
<span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1">« first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
        {% endif %}

        <span class="current">
            Page {{ page_obj.number }} sur {{ page_obj.paginator.num_pages }}.
        </span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last »</a>
        {% endif %}
    </span>
</div>

Je n'ai pas eu l'ocasion de tester Paginator jusqu'ici. Et c'est peut-être une mauvaise mise en bouche car je commence avec une page qui affiche un double queryset.

Je peux bien naviguer entre les pages, mais ça ne change rien que je sois de la page 1 à 8...

Ce n'est peut-être pas possible d'utiliser Paginator dans mon cas ?

Merci d'avance

Salut Gab !

Alors si je ne me trompe pas, tu utilises bien le Paginator mais le problème c'est que tu refais le filtre après avec les termes de la recherche.

Dans ta vue, tu crées d'abord une instance du Paginator avec paginator = Paginator(ideas | request_ideas, 1). Mais ensuite, dans ta méthode GET, tu filtres à nouveau tes requêtes ideas et request_ideas si une recherche est effectuée.

Et c'est là que ça pose problème : c'est comme si tu avais paginé une liste de tous tes objets Ideas (peu importe leur nom), puis que tu redéfinissais tes données avec une liste filtrée de ces objets (mais ici, seulement ceux qui contiennent le texte de la recherche).

Du coup il faudrait effectuer le filtrage avant de paginer :

def ideas_and_request_ideas_view(request):
    # Ici tu filtres les idées pour ne garder que celles qui correspondent à la recherche
    search = request.GET.get("search", "")
    ideas = Idea.objects.filter(name__icontains=search, status=True, paid=False, request=False)
    request_ideas = Idea.objects.filter(name__icontains=search, status=True, paid=False, request=True)

    # Et ensuite tu donnes ça au Paginator pour "paginer" les données à afficher qui ont déjà été filtrées
    paginator = Paginator(ideas | request_ideas, 1)
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    return render(request, "ideas/all.html", context={'ideas': ideas,
                                                      'request_ideas': request_ideas,
                                                      'page_obj': page_obj})

Gabriel Trouvé

Mentor

Décidemment j'ai du mal ce soir...

En faisant ça, que j'aille sur la page 1, 2, 3 ou 4 j'ai toujours la même chose d'affichée. Même sans recherche, juste en allant sur l'url.

Pourtant :

  1. J'ai bien mes querysets de base.

  2. Puis si'il y a une recherche on modifie le set.

  3. Et à la fin j'ai bien mon paginator.

def ideas_and_request_ideas_view(request):
    ideas = Idea.objects.filter(status=True, paid=False, request=False)
    request_ideas = Idea.objects.filter(status=True, paid=False, request=True)

    search = request.GET.get("search")
    if search:
        ideas = Idea.objects.filter(name__icontains=search, status=True, paid=False, request=False)
        request_ideas = Idea.objects.filter(name__icontains=search, status=True, paid=False, request=True)

    paginator = Paginator(ideas | request_ideas, 2)
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    return render(request, "ideas/all.html", context={'ideas': ideas,
                                                      'request_ideas': request_ideas, "page_obj": page_obj})

Salut Gab !

Dans ton template, tu utilises bien ton page_obj pour afficher les objets de la page courante ?

{% for idea in page_obj %}
    ...
{% endfor %}

Gabriel Trouvé

Mentor

Mais oui je n'avais pas compris...

Je suis allé voir un peu le code source.

Effectivement j'avais oublié d'utiliser mon objet Paginator()...

C'est tout bon en fait !

Merci Thibault !

Inscris-toi

(c'est gratuit !)

Inscris-toi

Tu dois créer un compte pour participer aux discussions.

Créer un compte

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.