Makina Blog

Le blog Makina-corpus

Wagtail : Créer ses modèles de type de contenu (partie 1)


On commence à avoir l'habitude d'initialiser son CMS directement depuis une interface web, cela incluant souvent de nombreux panneaux complexes. Wagtail reprend plutôt la philosophie Django et nous propose de définir les types de contenus comme des modèles.

Une connaissance des principes de base de Django est requise pour la lecture de cette article.

Initialisation de Wagtail

L' initialisation d'un site Wagtail est très similaire à celle d'un site Django : créer un environnement virtuel, installer wagtail, puis utiliser la commande wagtail. Il suffit ensuite de créer la base de données et un compte d'administrateur :

$ mkvirtualenv mon_site_wagtail
$ pip install wagtail
$ wagtail start mon_site_wagtail
$ cd mon_site_wagtail
$ python manage.py migrate
$ python manage.py createsuperuser

Nous avons deux applications créées par défaut: home et search. home contient un type de contenu tandis que search définis une vue permettant de faire des recherches.

Champs

Chaque type de contenu est en fait un modèle Django héritant du modèle Page. Ce modèle possède un certain nombre de champs par défaut (tel qu'un titre, un slug, …). La liste des champs par défaut est présent dans la documentation.

Les champs utilisés sont les mêmes que Django (CharField, DateTimeField, …), en plus des champs RichTextField, permettant l'utilisation d'un WYSIWYG, et StreamField, que nous verrons juste après. Créons notre premier type de contenu en modifiant HomePage :

class HomePage(Page):
    sous_titre = models.CharField(max_length=255)
    intro = RichTextField()
    image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )

L'ajout d'une image est une simple ForeignKey vers le modèle wagtailimages.Image de Wagtail. Il est possible de lier un document de la même facon avec le modèle wagtaildocs.Document.

StreamField

Un StreamField est un champ un peu particulier permettant le mélange de plusieurs type de champs de manière organisée. Une présentation est disponible sur YouTube. Voyons comment créer un StreamField :

class HomePage(Page):
    [...]
    corps = StreamField([
        ('titre', blocks.CharBlock(classname="full title")),
        ('paragraphe', blocks.RichTextBlock()),
        ('image', ImageChooserBlock()),
    ])

Un StreamField est une liste de blocks. La liste complète des blocks disponibles est dans la documentation officielle.

Bien, maintenant que nous avons définis les champs de notre type de contenu, il ne nous reste plus qu'a choisir où les afficher dans l'écran d'édition.

Panels

Wagtail propose plusieurs panneaux (onglets) pour organiser les champs. content\_panels pour le contenu en lui même, promote\_panels pour les métadonnées et settings\_panels pour les paramètres :

class HomePage(Page):
    # [...]

    content_panels = Page.content_panels + [
        FieldPanel('sous_titre'),
        ImageChooserPanel('image'),
        FieldPanel('intro', classname="full"),
        StreamFieldPanel('corps')
    ]

Un panneau est une liste de FieldPanels. Il en existe plusieurs types.

FieldPanel

FieldPanel pour tous les champs de base. FieldPanel peut prendre le paramètre classname pour ajouter une classe au champ. Wagtail met plusieurs classes utiles à disposition : - title, indiquant un champ titre. - full, permettant au champs de prendre toute la place à disposition. - col1 à col12, indiquant la taille en nombre de colonnes (sur douze) que le champ prendra.

StreamFieldPanel

StreamFieldPanel pour les StreamField :

ChooserPanel

Les ChooserPanel pour selectionner un objet déjà existant. Il en existe quatre différents : PageChooserPanel, ImageChooserPanel, DocumentChooserPanel ou SnippetChooserPanel :

Organiser les champs

Il existe trois types de FieldPanel permettant de mieux organiser les champs :

MultiFieldPanel

MultiFieldPanel permet de grouper des champs ensemble. Ajouter collapsible en classe permet de créer un accordéon pour ces champs. Ajouter collapsed permet d'avoir l'accordéon fermé par défaut.

content_panels = Page.content_panels + [
    MultiFieldPanel([
            FieldPanel('sous_titre'),
            ImageChooserPanel('image'),
        ],
        heading="Un MultiFieldPanel",
        classname="collapsible collapsed",
    ),
    FieldPanel('intro', classname="full"),
    StreamFieldPanel('corps')
]

FieldRowPanel

FieldRowPanel permet de réunir plusieurs champs sur une même ligne. Il est important de préciser classname avec la taille des colonnes pour que les champs s'affichent correctement :

content_panels = Page.content_panels + [
    FieldRowPanel([
        FieldPanel('sous_titre', classname="col6"),
        FieldPanel('intro', classname="col6"),
    ]),
    ImageChooserPanel('image'),
    StreamFieldPanel('corps')
]

InlinePanel

InlinePanel permet de gérer un autre modèle, et permet notamment de créer un champ multiple.

Les InlinePanels utilisent un modèle spécial, Orderable (Documentation) :

class HomePage(Page):
    [...]

    content_panels = Page.content_panels + [
        [...]
        InlinePanel('liens', label="Liens")
    ]

class HomePageLien(Orderable):
    page = ParentalKey(HomePage, related_name='liens')
    nom = models.CharField(max_length=255)
    url = models.URLField()

    panels = [
        FieldPanel('nom'),
        FieldPanel('url'),
    ]

ParentalKey est juste une ForeignKey utilisé pour django-modelcluster (pour plus d'information, voir la documentation).

Comme tout modèle Django, nous devons d'abord créer et faire tourner les migrations :

$ python manage.py makemigrations
$ python manage.py migrate

N'hésitez pas à consulter la Documentation officielle pour pousser plus loin.

Nous pouvons dès à présent créer nos premiers contenus. Mais il reste un dernier point à comprendre avant de se jeter la-dessus, et pas des moindres.

Hiérarchie

Wagtail organise les contenus par arborescence (hiérarchie). Comme tout arbre, il existe par défaut une page racine d'un site (oui, Wagtail est multisite par défaut, mais nous reviendrons sur ce point dans un prochain article). À cette page racine, on y rattache traditionnellement une page enfant de type page d'accueil. C'est le premier niveau. Puis à partir de cette page d'accueil, on aura des pages enfants de type listes (deuxième niveau) et enfin des pages de détails. Pour reprendre notre exemple, on va considérer que notre page d'accueil va contenir une page de blog qui listera les billets de blog en mode aperçu. Pour cela, il faut que cette page d'index de blog n'accepte que les pages de type blog comme enfant. Inversement, on peut définir dans les pages de blog que seule la page d'index peut être la parente. Pour y parvenir, Wagtail met à disposition deux attributs parent_page_types et subpage_types à définir dans les modèles de pages (Documentation).

Pour notre page d'accueil, nous allons donc créer un autre modèle BlogIndex qui n'acceptera que les pages de type blog en enfant :

class BlogIndex(Page):
    [...]
    subpage_types = ['app.BlogPage']

Et ajouter un modèle BlogPage qui n'autorisera que la(es) page(s) de type BlogIndex à être parente, et qui ne pourra pas avoir elle-même d'enfant :

class BlogPage(Page):
    [...]
    parent_page_types = ['app.BlogIndex']
    subpage_types = []

Conclusion

Vous savez désormais tout sur les Pages. Ou presque. Nous verrons dans la prochaine partie comment utiliser ce modèle ainsi que son manager.

Formations associées

Formations Django

Formation Django avancé

À distance (FOAD) Du 18 au 22 mars 2024

Voir la formation

Formations Django

Formation Django intégration

À distance (FOAD) 22 janvier

Voir la formation

Formations Django

Formation Django initiation

Nantes Du 12 au 14 mars 2024

Voir la formation

Actualités en lien

Image
Django PostgreSQL
07/11/2023

Utiliser des fonctions PostgreSQL dans des contraintes Django

Cet article vous présente comment utiliser les fonctions et les check constraints PostgreSQL en tant que contrainte sur vos modèles Django.

Voir l'article
Image
StreamField wagtail
15/06/2016

Wagtail : Comment écrire les templates (partie 3)

Il n'y a pas de vue à proprement parlé dans Wagtail. Tout est en fait géré dans le modèle. Nous pouvons ainsi modifier le template utilisé ou étendre son contexte en fonction du type de contenu sans problème.

Voir l'article
Image
Wagtail
15/06/2016

Wagtail : Utiliser le modèle Page ainsi que son Manager (partie 2)

Le modèle Page contient plusieurs méthodes spécifiques à l'outil Wagtail. C'est également le cas de son manager. Nous allons faire le tour de tout cela dans cet article.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus