Paginez le flux principal
Maintenant que nous avons le flux social, ajoutons-y la pagination. La pagination fonctionne en divisant une liste ou QuerySet en plusieurs morceaux de taille égale. On peut ensuite afficher chaque section sur sa propre page.
L’avantage principal de ce procédé ? La performance. Si nous avions des milliers ou même davantage d’instances de Photo
et Blog
dans la base de données, et que nous essayions de les charger toutes sur la page en même temps, le temps de chargement serait astronomique. C’est pourquoi il est préférable de paginer. Même les sites qui implémentent un défilement infini chargent et affichent leurs ressources par lots. Découvrez ci-dessous comment paginer la page d'accueil :
Pour paginer une page, utilisez la classe django.core.paginator.Paginator
.
Vous pouvez fournir n’importe quel itérable (c’est-à-dire une liste ou un QuerySet) à Paginator
, en plus du nombre d’instances dont vous avez besoin par page. La classe Paginator
divise alors l’itérable en objets Page
, et chacun d’entre eux contient les résultats pour une page individuelle.
La page sur laquelle vous êtes est alors stockée en tant que chaîne de requête dans l’URL.
C’est quoi, une chaîne de requête ?
Une chaîne de requête est une liste de paires clé-valeur qui est stockée dans l’URL. Elle est caractérisée par son apparition après un?
.
Si vous prenez l’URL https://fotoblog.com?page=5, la clé est page
, et la valeur est 5
.
Avec Django, vous pouvez y accéder dans la vue via l’objet request.GET
.
Donc, si vous appelezrequest.GET.get('page')
, vous obtiendrez5
.
Vous pourrez utiliser ensuite la méthode Paginator.get_page
pour obtenir un objet représentant la page sur laquelle vous êtes.
Essayons nous-mêmes avec notre flux principal.
from django.core.paginator import Paginator
def home(request):
blogs = models.Blog.objects.filter(
Q(author__in=request.user.follows) | Q(starred=True))
photos = models.Photo.objects.filter(
uploader__in=request.user.follows).exclude(
blog__in=blogs
)
blogs_and_photos = sorted(
chain(blogs, photos),
key=lambda instance: instance.date_created,
reverse=True
)
paginator = Paginator(blogs_and_photos, 6)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {'page_obj': page_obj}
return render(request, 'blog/home.html', context=context)
Mettez maintenant à jour le gabarit pour utiliser le paginateur. Plutôt que d’itérer dans la liste d’origine, vous itérez désormais danspage_obj
.
{% extends 'base.html' %}
{% load blog_extras %}
{% block content %}
<h2>Votre flux</h2>
{% for instance in page_obj %}
{% if instance|model_type == 'Blog' %}
{% include 'blog/partials/blog_snippet.html' with blog=instance %}
{% elif instance|model_type == 'Photo' %}
{% include 'blog/partials/photo_snippet.html' with blog=instance %}
{% endif %}
{% endfor %}
{% endblock content %}
Voyons à quoi ça ressemble :
Le flux est maintenant limité à six billets et photos par page, mais il n’y a aucun moyen de naviguer entre les pages.
Nous devons également ajouter une section à la fin qui donne le numéro de page à l’utilisateur et lui permette de naviguer vers l’avant et vers l’arrière.
La variable page_obj
a des attributs pratiques que vous pouvez utiliser pour générer ces éléments de navigation.
Voyons de quoi ça ressemble dans le gabarit.
{% extends 'base.html' %}
{% load blog_extras %}
{% block content %}
<h2>Votre flux</h2>
{% for instance in page_obj %}
{% if instance|model_type == 'Blog' %}
{% include 'blog/partials/blog_snippet.html' with blog=instance %}
{% elif instance|model_type == 'Photo' %}
{% include 'blog/partials/photo_snippet.html' with blog=instance %}
{% endif %}
{% endfor %}
<span>
{% if page_obj.has_previous %}
<a href="?page=1">« première</a>
<a href="?page={{ page_obj.previous_page_number }}">précédente</a>
{% endif %}
<span>
Page {{ page_obj.number }} sur {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">suivante</a>
<a href="?page={{ page_obj.paginator.num_pages }}">dernière »</a>
{% endif %}
</span>
{% endblock content %}
À quoi ressemble notre page maintenant ? On croise les doigts ! 🤞
Joli ! Nous pouvons désormais accéder à tous les billets et photos par le biais de ces éléments de navigation.
Maintenant que vous les avez ajoutés au flux principal, il est temps de faire la même chose avec le flux photo.
C'est à vous ! Paginez le flux photo
Allez-y, paginez le flux photo !
Vous devrez :
Mettre à jour la vue
photo_feed
pour créer une instance duPaginator
et inclure l’objetpage_obj
dans le contexte.Mettre à jour le
photo_feed.html
pour itérer danspage_obj
et non plus dans photos.Ajouter la section de navigation en bas de page dans
photo_feed.html
— indice — il s’agit d’un élément réutilisable que vous avez partagé avec plusieurs gabarits. Savez-vous comment l’inclure dans les deux sans vous répéter ?
Et votre site est terminé ! Félicitations ! N’oubliez pas de comparer la solution que vous avez trouvée pour votre dernier exercice avec la solution dans le dépôt GitHub.
En résumé
La pagination améliore la performance d’un site en divisant de gros itérables en morceaux plus petits.
Pour paginer une vue, donnez à la classe
Paginator
un itérable tel qu’un QuerySet ou une liste, ainsi que le nombre d’instances que vous voulez afficher par page.Accédez au numéro de page par une chaîne de requête et utilisez-le pour générer un page_obj que vous passerez au contexte du gabarit.
Utilisez un gabarit partiel pour inclure la section de navigation afin de paginer plusieurs pages.
Et maintenant que vous savez paginer les pages de votre site, le moment est venu de récapituler ce cours !