Index site wagtail

Introduction

En tant que développeur, j'ai ressenti le besoin de créer mon application web personnelle avec trois objectifs principaux :

  • Partager mes projets
  • Partager mes apprentissages via des articles
  • Disposer d'un back office pour la gestion de projets

Django s'est imposé naturellement comme choix de framework, étant donné mon expérience avec celui-ci. J'ai d'abord commencé le développement de façon traditionnelle, en créant mes propres modèles pour gérer les articles et les projets. Cependant, devoir gérer manuellement tous les aspects d'un CMS m'a fait réfléchir. C'est là que j'ai découvert Wagtail, qui m'a donné la possibilité de me coder mon propre CMS !

Le choix de Wagtail

Mon choix a été assez rapide. WordPress aurait pu être une option, mais en tant que développeur Django, il aurait été dommage de ne pas profiter de toute la puissance du framework. J'avais déjà développé un back office de gestion de projets avec Django, et en explorant les solutions CMS disponibles pour l'écosystème Django, deux options majeures sont ressorties : Wagtail et Django CMS. Wagtail s'est rapidement démarqué comme étant le plus adapté à mes besoins. En plongeant dans sa documentation j'ai été conquis par sa flexibilité et sa modernité !

Mais pourquoi pas Wordpress ou Joomla par exemple ?

Comme je le disais précédemment, en tant que développeur Django, il était peu cohérent d'utiliser une autre solution pour une application web personnelle, d'autant plus que celle-ci comprend un back-office avec une logique métier que je gère déjà avec Django.

Pour être honnête, si aucune librairie CMS Django n'avait existé, j'aurais simplement codé mon propre système de publication avec des modèles Django. Mais la découverte de Wagtail a rapidement résolu cette problématique, m'offrant le meilleur des deux mondes : la puissance de Django et les fonctionnalités d'un CMS moderne.

Les avantages de Wagtail

L'ergonomie de l'administration

Premièrement, lorsque vous installez Wagtail et que vous accédez à l'interface d'administration, l'ergonomie saute aux yeux !

Le tableau de bord est clair, sobre et efficace, permettant d'accéder rapidement à toutes les fonctionnalités essentielles :

  • Arborescence des pages
  • Recherche
  • Menu latéral qu'il est possible de personnaliser
  • Dernières modifications
  • ...

tableau de bord wagtail

Aussi, l'éditeur de contenu est remarquable ! Comme vous pouvez le voir sur la photo ci-dessous, il est très pratique :

Editeur wagtail

Et encore, je ne vais pas tout dévoiler ici, mais je parle pas mal de Wagtail sur ma chaine Youtube.

La gestion des publications

Je ne vais pas rentrer dans le détail ici, mais avec Wagtail, vous allez adapter le CMS à la façon dont vous voulez publier.

Vous allez créer des modèles de Page, que vous allez pouvoir réutiliser sur votre application web. Avec Wagtail on ne parle pas directement de Models à la Django, mais de Page (qui hérite de Models).

Dans mon cas, j'ai un modèle spécifique pour ma landing page :

class HomePage(GenericPage):
    body = RichTextField(blank=True)

    content_panels = GenericPage.content_panels + [
        FieldPanel('header'),
        FieldPanel('body')
    ]

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        context["last_article"] = BlogPage.objects.live().order_by("-date").first()
        context["project"] = FolioPage.objects.live().order_by("-date").first()
        return context

Bon ok, je viens de dire que les modèles Wagtail héritent de Page, mais ici mes modèles héritent de GenericPage. En réalité, j'ai moi même créé un modèle de Page abstrait (GenericPage), qui hérite lui même de Page. Je vous l'avais bien dit, c'est du Django :).

class GenericPage(Page):
    header = RichTextField(blank=True)

    class Meta:
        abstract = True

Mais le plus souvent, vous allez créer des modèles Page plus génériques. Par exemple, vous n'allez pas créer un modèle pour chaque article de blog. Dans l'exemple ci-dessous, j'ai un modèle pour la page d'index du blog, et un autre pour tous les articles :

class BlogIndexPage(GenericPage):
    content_panels = GenericPage.content_panels + [
        FieldPanel('header'),
    ]

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        blogpages = BlogPage.objects.child_of(self).live().order_by("-date")
        context["blogpages"] = blogpages
        return context


class BlogPage(GenericPage):
    main_image = models.ForeignKey(Image, on_delete=models.PROTECT, verbose_name="Image principale", related_name="+")
    date = models.DateField(verbose_name="Date de publication")
    body = StreamField([
        ("paragraphe", blocks.RichTextBlock()),
        ("code", CodeBlock()),
    ], use_json_field=True)
    tags = ClusterTaggableManager(through=BlogTaggedPage, blank=True)

    search_fields = GenericPage.search_fields + [
        index.SearchField("header"),
        index.SearchField("body")
    ]

    content_panels = GenericPage.content_panels + [
        MultiFieldPanel([
            FieldPanel("header"),
            FieldPanel("date"),
            FieldPanel("main_image")],
            heading="En-tête"),
        FieldPanel("body"),
        FieldPanel("tags")
    ]

Finalement il suffit de cliquer pour ajouter une Page, et choisir le modèle de Page souhaité :

Ajouter une page wagtail

Ici, au niveau de l'index du blog, j'ajoute un article de blog en sélectionnant le modèle voulu.

Cette structure de modèles nous permet aussi d'utiliser des fonctionnalités avancées comme les StreamFields, que vous pouvez voir dans le modèle BlogPage. C'est l'un des points forts de Wagtail que nous allons voir maintenant.

Les StreamFields

Les StreamFields sont l'une des fonctionnalités les plus puissantes de Wagtail. Dans le modèle BlogPage que j'ai présenté plus haut, vous avez peut-être remarqué cette ligne :

body = StreamField([
    ("paragraphe", blocks.RichTextBlock()),
    ("code", CodeBlock()),
], use_json_field=True)

C'est ce qui permet d'avoir un contenu dynamique et modulaire. Au lieu d'avoir un unique champ de texte pour le contenu, je peux alterner entre différents types de blocs : texte, blocs de code, images, vidéos, etc. Le tout de manière totalement flexible.

En cliquant sur le "+", je peux choisir quel type de bloc je vais utiliser. Dans mon exemple je n'ai que deux blocs disponibles (Code et Paragraphe), mais vous pouvez personnaliser ça à votre guise !

Streamfields wagtail

La publication collaborative

Et bien sûr vous pouvez enregistrer votre publication sans la publier.

Publication wagtail

Aussi, vous pouvez travailler à plusieurs sur les publications. De ce fait, il est possible de tirer profit du système de workflow intégré à Wagtail.

Les éditeurs peuvent écrire une publication, et les modérateurs peuvent approuver, ou soumettre des corrections. Il est même possible de laisser des commentaires à différents endroits d'une publication.

Commentaire wagtail

Un autre point fort de Wagtail est son système de révisions. Chaque modification d'une page est enregistrée, ce qui permet de :

  • Voir l'historique complet des modifications
  • Comparer les différentes versions
  • Restaurer une version précédente si nécessaire

Révisions wagtail

La gestion des médias

Wagtail intègre nativement un système de gestion des médias dans son interface d'administration. Vous y retrouvez deux sections : "Images" et "Documents".

L'interface est pensée pour être pratique :

  • Upload par drag & drop
  • Prévisualisation des images
  • Recherche
  • Tags pour organiser vos médias

Gallerie image wagtail

Drag and drop wagtail

Documents vides wagtail

Les snippets

Depuis le début je répète que Wagtail est développé avec Django. Et bien les snippets en sont la preuve parfaite ! Ils permettent d'intégrer facilement vos modèles Django dans l'interface d'administration Wagtail.

Imaginez un modèle Django Comment :

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Utilisateur")
    page = models.ForeignKey("article.ArticlePage", on_delete=models.CASCADE, related_name="comments")
    text = models.TextField(verbose_name="Commentaire")

    def __str__(self):
        return f"{self.user} - {self.page.title}"

J'aimerais pouvoir l'intégrer dans mon administration Wagtail. Car évidemment, vous pouvez switcher entre l'administration Wagtail et Django, mais c'est quand même mieux si l'on peut regrouper nos modèles dans une seule administration.

C'est évidemment possible ! Il suffit d'utiliser le décorateur @register_snippet sur votre modèle Django, de définir l'attribut panels, et hop ! Votre modèle apparaît dans la section "Snippets" de l'administration Wagtail.

@register_snippet
class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Utilisateur")
    page = models.ForeignKey("article.ArticlePage", on_delete=models.CASCADE, related_name="comments")
    text = models.TextField(verbose_name="Commentaire")

    def __str__(self):
        return f"{self.user} - {self.page.title}"

    panels = [
        FieldPanel("user"),
        FieldPanel("text"),
        FieldPanel("page")
    ]

Le mot de la fin

Et voilà ! J'espère vous avoir donné un aperçu de Wagtail et des raisons qui m'ont poussé à l'utiliser pour mon site. Pour résumer, Wagtail c'est :

  • Un CMS qui s'adapte à vos besoins (codez votre CMS !)
  • Une interface d'administration super ergonomique
  • Toute la puissance de Django
  • Des fonctionnalités modernes comme les StreamFields
  • La possibilité de travailler à plusieurs

Si vous voulez en savoir plus, j'ai enregistré une vidéo de 3h sur wagtail.


Retour