Écrire votre première application Django, partie 2

Ce tutoriel débute là où le Tutoriel 1 s’achève. Nous continuons l’écriture de l’application Web de sondage et nous nous focaliserons sur la génération automatique de la partie administration d’un site par Django.

Philosophie

La création de la partie administrative d’un site pour que votre équipe, ou vos clients, puissent ajouter, modifier et supprimer du contenu n’est pas la partie la plus folichonne à réaliser et ne demande pas beaucoup de créativité. Pour cette raison, Django automatise entièrement la création de l’interface d’administration pour les modèles.

Django a été écrit dans l’environnement d’une salle de rédaction, avec une séparation très nette entre la publication des contenus et le site public. Les gestionnaires de sites utilisent le système pour ajouter de nouveaux articles, événements, résultats sportifs, etc, et ce contenu est affiché sur le site public. Django résout la question de la création d’une interface d’administration unifiée pour que les gestionnaires de site éditent le contenu.

La partie administration n’est pas destinée à être utilisée par les internautes. Elle est destinée aux administrateurs du site.

Activer la partie administration

La partie administration d’un site Django n’est pas activée par défaut. Pour l’activer, faites les trois choses suivantes:

  • Décommentez "django.contrib.admin" dans le paramètre INSTALLED_APPS.

  • Exécutez python manage.py syncdb. Puisque vous avez ajouté une nouvelle application dans INSTALLED_APPS, la base de données doit être actualisée.

  • Éditez votre fichier mysite/urls.py et décommentez les lignes qui référencent la partie admin – il y a trois lignes à décommenter en tout. Ce fichier est un URLconf; nous approfondirons URLconfs dans le prochain tuto. Pour l’instant, tout ce que vous avez besoin de savoir c’est qu’il définit les racines des URL de vos applications. Au final, vous devriez avoir un fichier urls.py qui ressemble à ceci :

    from django.conf.urls import patterns, include, url
    
    # Décommentez les deux prochaines lignes pour activer admin:
    from django.contrib import admin
    admin.autodiscover()
    
    urlpatterns = patterns('',
        # Exemples:
        # url(r'^$', '{{ project_name }}.views.home', name='home'),
        # url(r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')),
    
        # Décommentez la ligne admin/doc line ci-dessous pour activer la documentation de l'admin:
        # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
    
        # Décommentez la ligne suivante pour activer l'admin :
        url(r'^admin/', include(admin.site.urls)),
    )
    

    (Les lignes en gras sont celles qui doivent être décommentées.)

Démarrer le serveur de développement

Démarrez le serveur de développement et explorez la partie admin du site.

Le premier tuto vous a dit que le démarrage du serveur de développement se fait comme ceci :

python manage.py runserver

Maintenant, ouvrez un navigateur internet et allez sur “/admin/” de vote domaine local – par exemple, http://127.0.0.1:8000/admin/. Vous devriez voir le login de l’interface d’admin :

Django admin login screen

Ça ne correspond pas à ce que vous avez ?

Si à ce stade vous avez une page d’erreur à la place du login de la partie admin et qu’elle vous dit quelque chose comme ceci:

ImportError at /admin/
cannot import name patterns
...

c’est que vous utilisez probablement une version de Django qui ne correspond pas à ce tutoriel. Vous avez le choix entre basculer vers l’ancien tutoriel ou vers la nouvelle version de Django.

Entrer dans le site d’administration

Maintenant, loggez-vous (vous avez créé un compte super utilisateur dans la première partie de ce tutoriel, vous vous en souvenez ? Si vous ne l’avez pas fait ou si vous avez oublié le mot de passe, vous pouvez en create another one (*en créer un autre*).) Vous devriez obtenir la page d’index de la partie admin du site Django :

Django admin index page

Vous devriez voir quelques types de contenus éditables, y compris les groupes, les utilisateurs et les sites. Ce sont des fonctionnalités du core que Django fournit par défaut.

Rendre le sondage modifiable dans la partie admin

Mais où est donc notre application sondage ? Elle n’est pas affichée sur la page d’index.

Une seule chose à faire : dire à admin que l’objet Poll a une interface d’administration. Pour cela, créez un fichier appelé admin.py dans votre dossier polls, et éditez-le pour qu’il ressemble à ça:

from polls.models import Poll
from django.contrib import admin

admin.site.register(Poll)

Vous devrez redémarrer le serveur de développement pour voir les changements. Normalement, le serveur recharge automatiquement le code chaque fois que vous modifiez un fichier, mais la création d’un nouveau fichier ne déclenche pas le rechargement automatique.

Explorer les fonctionnalités libres de la partie administration

Maintenant que nous avons enregistré Poll, Django sait qu’il doit être affiché dans l’index de la partie administration :

Django admin index page, now with polls displayed

Cliquez sur “Polls.” Vous êtes maintenant dans la page “change list” des sondages. Cette page affiche tous les sondages de la base de données et vous permet d’en choisir un pour le modifier. Il y a le sondage “What’s up?” créé dans le premier tuto :

Polls change list page

Cliquez sur le sondage “What’s up?” pour le modifier :

Editing form for poll object

Quelques remarques opportunes :

  • Le formulaire est automatiquement généré à partir du modèle Poll.
  • Les différents types de champs (DateTimeField, CharField) correspondent à leur widget HTML pour leur saisie. Chaque type de champ sait comment s’afficher dans la partie admin de Django.
  • Chaque DateTimeField dispose de raccourcis JavaScript . Les dates ont un raccourci “Today” et un calendrier pop-up, et les heures ont un raccourci “Now” et un popup adapté qui liste les heures les plus courantes.

La fin de la page vous donne quelques options :

  • Save – Sauvegarde les modifications et retourne à la liste de cet objet.
  • Save and continue editing – Sauvegarde les modifications et recharge la page d’admin de cet objet.
  • Save and add another – Sauvegarde les modifications et charge un nouveau formulaire vierge pour l’objet.
  • Delete – Affiche une page de confirmation pour la suppression.

Si la valeur de “Date published” ne correspond pas à l’heure de création du sondage, c’est que vous n’avez probablement pas bien paramétré la valeur de TIME_ZONE Modifiez-le, rechargez la page et vérifiez que la bonne valeur est affichée.

Changez “Date published” en cliquant sur les raccourcis “Today” et “Now”. Puis cliquez sur “Save and continue editing.” Cliquez ensuite sur “History” en haut à droite. Vous verrez un listing de toutes les modifications faites sur cet objet via l’admin Django, avec le timbre à date et le nom d’utilisateur qui a effectué la modif :

History page for poll object

Personnaliser le formulaire d’administration

Prenez quelques instant pour vous émerveiller devant tout ce code que vous n’avez pas eu à écrire. En enregistrant le modèle Poll avec admin.site.register(Poll), Django a été capable de construire un affichage par défaut. Vous voudrez sans doute personnaliser le formulaire d’administration. Vous le ferez en communiquant vos options à Django, lors de l’enregistrement de l’objet.

Voyons comment ça marche en réorganisant les champs du formulaire d’édition. Remplacez la ligne admin.site.register(Poll) avec:

class PollAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question']

admin.site.register(Poll, PollAdmin)

Vous suivrez ce modèle – créer un modèle admin objet, le passer en deuxième argument à admin.site.register() – chaque fois que vous devrez modifier les options d’admin pour un objet.

La moodif précédente place le champ “Publication date” avant le champ “Question” :

Fields have been reordered

Avec seulement deux champs, ce n’est pas très impressionnant. Mais pour les formulaires d’administration qui contiennent des douzaines de champs, choisir un ordre intuitif est un avantage ergonomique non négligeable.

Et à propos des formulaires comportant des douzaines de champs, vous voudrez peut-être diviser le formulaire en plusieurs zones (fieldsets):

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

admin.site.register(Poll, PollAdmin)

Le premier élément de chaque tuple dans fieldsets est le titre du fieldset. Voici à quoi ressemble le formulaire maintenant :

Form has fieldsets now

Vous pouvez attribuer des classes HTML à chaque fieldset de façon arbitraire. Django fournit une classe "collapse" qui affiche un fieldset donné initialement replié. C’est utile lorsque vous avez un long formulaire qui contient des champs peu utilisés:

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
Fieldset is initially collapsed

Ajouter des objets liés

OK, nous avons notre page d’administration pour Poll. Mais un Poll dispose de Choices, multiples, et la page d’admin n’en affiche aucun.

Pour l’instant.

Il y a deux façons de résoudre ce problème. La première est d’enregistrer Choice avec admin, tout comme on l’a fait avec Poll. C’est facile:

from polls.models import Choice

admin.site.register(Choice)

Désormais “Choices” est une option disponible dans l’admin Django. Le formulaire The “Add choice” ressemble à ceci:

Choice admin page

Dans ce formulaire, le champ “Poll” est une liste déroulante contenant chaque sondage enregistré dans la base de données. Django sait qu’une clé étrangère (ForeignKey) doit être représentée par une liste déroulante (<select>) dans la partie admin. Dans notre exemple, il n’y a pour l’instant qu’un sondage.

Remarquez aussi le lien “Add Another” à côté de “Poll.” Chaque objet avec une ForeignKey le liant à un autre objet reçoit ce type de lien. Lorsque vous cliquez sur “Add Another,” vous obtiendrez un formulaire “Add poll” dans une fenêtre pop-up. Si vous ajoutez un sondage dans cette fenêtre et cliquez sur “Save,” Django sauvegardera le sondage dans la base de données, l’ajoutera dynamiquement à la liste déroulante et en fera l’item sélectionne dans le formulaire “Add choice” que vous regardiez.

Mais en fait, ce n’est pas une façon efficace d’ajouter des objets Choice au système. Ce serait mieux si vous pouviez ajouter plusieurs Choice directement lors la création de l’objet Poll. Faisons-le.

Enlevez l’appel register() du modèle Choice. Puis éditez le code d’enregistrement de Poll pour obtenir:

class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]

admin.site.register(Poll, PollAdmin)

Cela indique à Django: « les objets Choice sont édités dans la page d’admin de Poll. Par défaut, fournis assez de champs pour 3 choix. »

Chargez la page “Add poll” pour voir ce que ça donne, vous aurez peut-être à relancer le serveur de développement :

Add poll page now has choices on it

Voilà comment ça marche : il y a trois emplacements pour les Choices liés – comme spécifié avec extra – et chaque fois que vous revenez sur la page “Change” d’un objet déjà créé, vous obtenez trois nouveaux emplacements.

Il y a quand même un petit problème. Ça prend pas mal de place d’afficher tous les champs pour saisir les objets Choice liés. Pour cette raison, Django propose la saisie des objets liés sous forme de tableau; il vous suffit juste de modifier la déclaration ChoiceInline comme ceci:

class ChoiceInline(admin.TabularInline):
    #...

Avec TabularInline (au lieu de StackedInline), les objets liés sont affichés de façon plus ramassée, sous forme de tableau :

Add poll page now has more compact choices

Vous remarquerez qu’une colonne supplémentaire (“Delete?”) permet de supprimer les lignes ajoutées via le bouton “Add Another Choice” et qu’il y a des lignes avec des valeurs déjà sauvegardées.

Personnaliser l’administration des listes de modifications

Maintenant que la page d’administration de Poll est ok, occupons-nous de modifier la page “change list” – celle qui affiche tous les sondages du système.

Voilà à quoi elle ressemble pour l’instant :

Polls change list page

Par défaut, Django affiche le str() de chaque objet. Mais parfois, ce serait plus pratique si on pouvait afficher des champs individuels. pour cela, il faut utiliser l’option d’administration list_display qui est un tuple de noms de champs à afficher, en colonnes, sur la page des modifs de l’objet:

class PollAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question', 'pub_date')

Pour la bonne bouche, ajoutons aussi la méthode personnalisée was_published_recently vue dans le premier tuto:

class PollAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question', 'pub_date', 'was_published_recently')

Maintenant, la page d’administration de modifs pour poll ressemble à ceci :

Polls change list page, updated

Vous pouvez cliquer sur les entêtes de colonne pour trier les valeurs – sauf pour was_published_recently car le tri des résultats fournis par une méthode arbitraire n’est pas supporté. Notez également que l’entête de colonne de was_published_recently est, par défaut, le nom de la méthode (avec les underscores remplacés par des espaces), et que chaque ligne contient la représentation en string de la sortie.

Vous pouvez améliorez ça en donnant quelques attributs à cette méthode (dans models.py) comme ceci:

class Poll(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'

Modifiez encore votre fichier admin.py et ajoutez cette amélioration à la page Liste des modifications pour Poll : Filters. Ajoutez la ligne suivante à PollAdmin:

list_filter = ['pub_date']

Cela ajoute une barre latérale (sidebar en VO. NdT) “Filter” qui permet aux utilisateurs de filtrer la Liste des modifications sur le champ pub_date:

Polls change list page, updated

Le type de filtre affiché dépend du type de champ sur lequel porte le filtre. Comme pub_date est un DateTimeField, Django sait fournir les options de filtre appropriées : “Any date,” “Today,” “Past 7 days,” “This month,” “This year.”

Cela a meilleure allure. Ajoutons des possibilités de recherches:

search_fields = ['question']

Cela ajoute une zone de recherche en haut de la page. Lorsqu’un utilisateur saisira des mots à rechercher, Django les cherchera dans le champ question. Vous pouvez utiliser autant de champs que vous le souhaitez – mais comme Django utilise la clause LIKE dans la requête, soyez raisonnable, pour ne pas froisser vote base de données.

Enfin, comme l’objet Poll comporte des dates, ça serait bien pratique de pouvoir classer par date. Ajoutez cette ligne:

date_hierarchy = 'pub_date'

Cela ajoute une navigation hiérarchique, par date, en haut de chaque page Liste de modifications. Au premier niveau, on affiche toutes les années disponibles. Puis on descend aux mois et, en dernier lieu, aux jours.

C’est le moment opportun pour dire que les Listes de modifications vous donnent une totale liberté pour la pagination. Par défaut, 100 items par page sont affichés. La pagination, les zones de recherche, les filtres, les hiérarchies pour les dates et le tri via les entêtes de colonne, tout marche ensemble, puisque c’est ainsi que cela doit marcher.

Personnaliser le look and feel de la page d’administration

Franchement, mettre “Django administration” en haut de chaque page est ridicule. En fait, c’est juste un texte de substitution (placeholder text en VO. NdT).

C’est facile à changer. En utilisant toutefois le système de mises en page de Django. Les pages d’administration de Django sont générées par Django lui-même, et ses interfaces utilisent donc le système de mises en page de Django.

Ouvrez votre fichier de paramètres (mysite/settings.py) et regardez le paramètre TEMPLATE_DIRS setting. TEMPLATE_DIRS est un tuple des dossiers à vérifier lors du chargement des templates Django. C’est un path de recherche.

Par défaut, TEMPLATE_DIRS est vide. Alors ajoutons-lui une ligne, pour dire à Django où se trouvent nos templates:

TEMPLATE_DIRS = (
    '/home/my_username/mytemplates', # Modifiez pour y mettre votre propre dossier.
)

Maintenant, copiez le template admin/base_site.html depuis le répertoire par défaut des templates admin de Django, situé dans le code-source de Django (django/contrib/admin/templates) vers un sous-dossier admin de n’importe quel dossier indiqué dans TEMPLATE_DIRS. Par exemple, si votre TEMPLATE_DIRS contient '/home/my_username/mytemplates', comme ci-dessus, copiez django/contrib/admin/templates/admin/base_site.html vers /home/my_username/mytemplates/admin/base_site.html. N’oubliez pas ce sous-dossier admin.

Où se trouvent les fichiers source de Django ?

Si vous avez du mal à localiser les fichiers source de Django dans votre système, exécutez la commande suivante :

python -c "
import sys
sys.path = sys.path[1:]
import django
print(django.__path__)"

Ensuite, modifiez le fichier et remplacez le texte générique de Django par votre propre texte.

Le fichier template contient un paquet de texte comme {% block branding %} et {{ title }}. Les balises {% et {{ font partie du langage de template de Django. Quand Django mouline admin/base_site.html, ce langage de template est utilisé pour produire la page HTML finale. Ne vous inquiétez pas si vous ne comprenez pas les template maintenant – nous aborderons cet aspect de Django dans le tuto 3.

Sachez que tout template par défaut de pages d’admin de Django peut être surchargé. Pour surcharger un template, faites-là même chose que pou base_site.html – copiez-le du dossier par défaut vers votre dossier personnalisé, et faites les modifs.

Les lecteurs perspicaces demanderont : « mais si TEMPLATE_DIRS était vide par défaut, comment Django a-t-il trouvé les templates d’admin par défaut ? » La réponse est que Django, par défaut, cherche automatiquement un sous-dossier templates/ dans chaque package d’applications, pour l’utiliser en solution de repli. Consultez template loader documentation pour la doc complète.

Personnalisez la page index d’Admin

De la même façon, vous voudrez peut-être personnaliser le look and feel de la page index de l’administration.

Elle affiche par défaut toutes les applications INSTALLED_APPS qui ont été enregistrées avec l’application admin, dans l’ordre alphabétique. Vous voudrez peut-être apporter de substantielles modifications à la mise en page. Après tout, la page d’index est sans doute la page la plus importante de l’administration et elle devrait être simple à utiliser.

Le template à personnaliser est admin/index.html. (faites la même chose qu’avec admin/base_site.html dans la précédente section. – copiez-le depuis le dossier par défaut vers votre dossier de templates personnalisés). Éditez le fichier et vous verrez qu’il utilise une variable de template appelée app_list.Cette variable contient chaque application Django installée. Au lieu de l’utiliser, vous pouvez coder en dur les liens vers les pages d’admin d’objets en particulier, de la façon qui vous semble la plus appropriée. Une fois encore, ne vous inquiétez pas si vous ne comprenez pas le langage de template – nous l’approfondirons dans le tuto 3.

Quand vous serez à l’aise avec la partie administration du site, lisez la troisième partie de ce tuto pour commencer à travailler sur les vues publiques des sondages.

Contact