• Aucun résultat trouvé

Utilisation concrète dans une vue

Nous avons vu comment utiliser la pagination de façon autonome, maintenant nous allons l'utiliser dans un cas concret. Nous reprenons notre vue simple (pas celle utilisant les vues génériques) du TP sur la minification d'URL :

Code : Python

def liste(request):

"""Affichage des redirections"""

minis = MiniURL.objects.order_by('-nb_acces')

return render(request, 'mini_url/liste.html', locals())

Nous allons tout d'abord ajouter un argument page à notre vue, afin de savoir quelle page l'utilisateur souhaite voir. Pour ce faire, il y a deux méthodes :

Passer le paramètre page via un paramètre GET (/url/?page=1) ;

Modifier la définition de l'URL et la vue pour prendre en compte un numéro de page (/url/1 pour la première page). Nous traiterons ici le second cas. Le premier cas se résume à un simple request.GET.get('page') dans la vue pour récupérer le numéro de page. Nous modifions donc légèrement notre vue pour le paramètre page :

Code : Python - mini_url/views.py

def liste(request, page=1):

"""Affichage des redirections"""

minis = MiniURL.objects.order_by('-nb_acces')

return render(request, 'mini_url/liste.html', locals())

Et notre fichier urls.py :

Code : Python - mini_url/urls.py

urlpatterns = patterns('mini_url.views',

url(r'^$', 'liste', name='url_liste'), # Pas d'argument page précisé -> vaudra 1 par défaut

url(r'^(?P<page>\d)$', 'liste', name='url_liste'), # …

Nous créons donc un objet Paginator à partir de cette liste, comme nous avons pu le faire au début de ce chapitre. Nous avons également vu que Paginator permettait de récupérer les objets d'une page précise : c'est ce que nous utiliserons désormais pour renvoyer au template la liste d'URL à afficher.

from django.core.paginator import Paginator, EmptyPage # Ne pas oublier l'importation

def liste(request, page=1):

"""Affichage des redirections"""

minis_list = MiniURL.objects.order_by('-nb_acces')

paginator = Paginator(minis_list, 5) # 5 liens par page try:

# La définition de nos URL autorise comme argument « page » uniquement des entiers,

# nous n'avons pas à nous soucier de l'erreur PageNotAnInteger

minis = paginator.page(page) except EmptyPage:

# Nous vérifions toutefois que nous ne dépassons pas la limite de page

# Par convention, nous renvoyons la dernière page dans ce cas

minis = paginator.page(paginator.num_pages) return render(request, 'mini_url/liste.html', locals())

En ajoutant 5 lignes de code (sans prendre en compte les commentaires), nous disposons désormais d'une pagination robuste, gérant tous les cas limites. Si vous testez la vue actuellement, vous verrez que l'adresse http://127.0.0.1:8000/m/

(attention, l'URL dépend de la configuration que vous avez utilisée durant le TP) renvoie les 5 premières URL (ajoutez-en si vous en avez moins), http://127.0.0.1:8000/m/2 les 5 suivantes, etc.

Passons désormais au template. En effet, pour l'instant il est impossible de passer d'une page à l'autre sans jouer avec l'URL et il est impossible de savoir le nombre de pages qu'il y a. Pour renseigner toutes ces informations, nous allons utiliser les

informations que nous avons vues précédemment :

Code : Jinja

<h1>Le raccourcisseur d'URL spécial crêpes bretonnes !</h1> <p><a href="{% url 'url_nouveau' %}">Raccourcir une URL.</a></p> <p>Liste des URL raccourcies :</p>

<ul>

{% for mini in minis %}

<li> <a href="{% url 'url_update' mini.code %}">Mettre à jour</a> - <a href="{% url 'url_delete' mini.code %}">Supprimer</a>

| {{ mini.url }} via <a href="http://{{ request.get_host }}{% url 'url_redirection' mini.code %}">

{{ request.get_host }}{% url 'url_redirection' mini.code %}

</a> {% if mini.pseudo %}par {{ mini.pseudo }}{% endif %}

({{ mini.nb_acces }} accès)</li>

{% empty %}

<li>Il n'y en a pas actuellement.</li>

{% endfor %}

</ul>

<div class="pagination"> <span class="step-links">

{% if minis.has_previous %}

<a href="{% url 'url_liste' minis.previous_page_number %}">Précédente</a> -

{% endif %}

<span class="current">

Page {{ minis.number }} sur {{ minis.paginator.num_pages }}

</span>

{% if minis.has_next %}

- <a href="{% url 'url_liste' minis.next_page_number %}">Suivante</a>

</span> </div>

Nous utilisons bien ici les méthodes has_next et has_previous pour savoir s'il faut afficher les liens « Précédent » et « Suivant ». Nous profitons également de l'attribut num_pages de Paginator afin d'afficher le total de pages.

Un bon conseil que nous pouvons vous donner, et en même temps un bon exercice à faire, est de créer un template générique gérant la pagination et de l'appeler où vous en avez besoin, via {% include "pagination.html" with liste=minis view="url_liste" %}.

Vous pouvez maintenant adapter la pagination comme vous voulez en modifiant la ligne appelant Paginator !

Code : Python

paginator = Paginator(minis_list, 20, 5) # 20 liens par page, avec un minimum de 5 liens sur la dernière

Nous en avons fini avec la pagination. Ce module est l'exemple le plus frappant de ce que nous pouvons faire avec Django en seulement quelques lignes, tout en changeant très peu de code par rapport à la base de départ.

En résumé

La classe django.core.paginator.Paginator permet de générer la pagination de plusieurs types de listes d'objets et s'instancie avec au minimum une liste et le nombre d'éléments à afficher par page.

Les attributs et méthodes clés de Paginator à retenir sont p.num_pages et p.page(). La classe Page a notamment les méthodes has_next(), has_previous() et est itérable afin de récupérer les objets de la page courante.

Il est possible de rendre la pagination plus pratique en prenant en compte l'argument orphans de Paginator. Pensez à uniformiser vos paginations en terme d'affichage au sein de votre site web, pour ne pas perturber vos visiteurs.

L'internationalisation

De nos jours, la plupart des sites web proposent plusieurs langues à leurs utilisateurs, et ciblent même la langue par défaut en fonction du visiteur. Ce concept apporte son lot de problèmes lors de la réalisation d'un site : que faut-il traduire ? Quelle méthode faut-il utiliser pour traduire facilement l'application, sans dupliquer le code ?

Nous allons voir dans ce chapitre comment traduire notre site en plusieurs langues, de façon optimale sans dupliquer nos templates et vues, via des méthodes fournies dans Django et l'outil gettext permettant de créer des fichiers de langue. Sachez que par convention en informatique le mot « internationalisation » est souvent abrégé par « i18n » ; cela est dû au fait que 18 lettres séparent le « i » du « n » dans ce mot si long à écrire ! Nous utiliserons également cette abréviation tout au long de ce chapitre.