Si vous avez de nombreux articles sur votre site Wagtail, il peut être utile de les commander par thèmes. Dans ce didacticiel, on explique comment créer des thèmes et des pages thématiques avec tous les articles par thème.
On crée un modèle de thème en mettant un Wagtail snippet (extrait) dans notre models.py
avant ArticlePage
:
from wagtail.snippets.models import register_snippet
@register_snippet
class Theme(models.Model):
name = models.CharField(max_length=255)
panels = [
FieldPanel('name'),
]
def __str__(self):
return self.name
Le modèle a un seul champ appelé name
, qui peut être créé et édité dans admin, dans un menu séparé Snippets. On crée une relation entre une page d'article et un ou plusieurs thèmes en ajoutant le champ suivant à notre modèle ArticlePage
(importez ParentalManyToManyField
de modelcluster.fields
):
themes = ParentalManyToManyField(Theme, blank=True, related_name='articlepages', verbose_name=_("Themes"))
et aux content_panels
d'ArticlePage
(importez forms
de Django):
FieldPanel('themes', widget=forms.CheckboxSelectMultiple),
Cela nous permettra de choisir les thèmes pertinents pour chaque article et de récupérer tous les articles relatifs à un thème via le related_name
articlepages
. Notez qu'il n'est pas utile d'ajouter null = True
à un ManyToManyField
, comme mentionné dans la documentation. Définissez maintenant un modèle ThemePage
:
from wagtail.snippets.edit_handlers import SnippetChooserPanel
class ThemePage(TranslatablePage):
theme = models.ForeignKey(Theme, on_delete=models.SET_NULL, null=True, related_name='themepages')
intro = RichTextField(blank=True)
image = models.ForeignKey(
'wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+'
)
caption = models.CharField(blank=True, null=True, max_length=250)
def articlepages(self):
return self.theme.articlepages.filter(language=self.language).live().order_by('-first_published_at')
content_panels = TranslatablePage.content_panels + [
SnippetChooserPanel('theme'),
FieldPanel('intro', classname='full'),
ImageChooserPanel('image'),
FieldPanel('caption'),
]
Ici, on utilise un ForeignKey
pour connecter le thème et la page de thème; la raison en est qu'on aura des pages en plusieurs langues concernant un thème. Si vous n'aviez qu'une seule langue, vous pourriez opter pour un OneToOneField
. On définit une méthode articlepages
pour classer les articles dans l'ordre chronologique inverse, comme on l'a fait dans un tutoriel précédent avec notre modèle ArticleIndexPage
. On veut uniquement des pages d'articles dans la même langue, on filtre donc par le champ language
du modèle TranslatablePage
. Étant donné qu'on a choisi exactement les mêmes noms de champ et related_name
que pour le modèle ArticleIndexPage
, le modèle theme_page.html
pour une page de thème avec tous les articles sur ce thème peut être identique au modèle article_index_page.html
qu'on a créé dans un didacticiel précédent:
{% include "article_index_page.html" %}
On veut également une page d'index avec un aperçu de tous nos thèmes. Le modèle peut être simple:
class ThemeIndexPage(TranslatablePage):
intro = RichTextField(blank=True)
# Specifies that only ThemePage objects can live under this index page
subpage_types = ['ThemePage']
content_panels = TranslatablePage.content_panels + [
FieldPanel('intro', classname='full'),
]
Il ressemble au modèle d'ArticleIndexPage
, avec subpage_types
indiquant qu'on veut uniquement les pages ThemePage
comme sous-pages. Le modèle theme_index_page.html
est presque le même que celui de ArticleIndexPage
, seulement ici on va parcourir la page.get_children
pour afficher toutes les pages de thème; vous pouvez le trouver dans le référentiel.
On aimera également afficher les thèmes sur notre page d'accueil. Ajoutez au modèle de page d'accueil un titre de section de thème, une introduction et un lien vers une page où on mettra tous les thèmes:
theme_section_title = models.CharField(
null=True,
blank=True,
max_length=255,
help_text=_("Title to display above the theme section"),
)
theme_section_intro = RichTextField(blank=True)
theme_section = models.ForeignKey(
TranslatablePage,
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
help_text=_("Featured section for the homepage. Will display all themes."),
verbose_name=_("Theme section"),
)
Ajoutez au modèle home_page.html
le titre et l'introduction et un conteneur avec le code suivant (le code complet dans le référentiel):
{% for childpage in page.theme_section.get_children %}
<div class="col-auto mb-3">
<div class="card theme">
<a href="{{ childpage.url }}">
{% if childpage.specific.image %}
{% image childpage.specific.image fill-320x240 class="img-front rounded-circle" %}
{% else %}
<img alt="" src="{% static 'images/transparent.png' %}" width="320" height="240" class="img-default rounded-circle">
{% endif %}
<img alt="" src="{% static 'images/transparent.png' %}" width="320" height="240" class="img-background rounded-circle">
<div class="card-img-overlay">
<br><h5 class="card-title text-center">{{ childpage.title }}</h5>
<p class="card-subtitle text-center">{{ childpage.specific.intro|striptags|truncatewords:15 }}</p>
</div>
</a>
</div>
</div>
{% endfor %}
Ceci est très similaire à ce qu'on a créé dans un didacticiel précédent pour afficher un certain nombre d'articles sur la page d'accueil: on utilise l'image de la page de thème pour créer une carte avec un lien vers ce thème, et on crée un effet de superposition avec une deuxième image transparente qu'on stylise dans notre CSS. Les cartes sont cette fois des ellipses.
Pour rendre notre page d'accueil un peu plus vivante, on peut ajouter un carrousel avec des images de tous les thèmes et de leurs titres. Il s'agit d'un composant Bootstrap standard, on ne répétera donc pas le code html ici. Pour parcourir les thèmes, on utilise une clause for
Django standard. On récupéra les thèmes avec page.theme_section.get_children
, utilise la balise image
pour afficher les images et la balise pageurl
pour créer un lien vers l'url d'une page.
On aimera également montrer des petits badges avec tous les thèmes pertinents au-dessus de chaque article et avec un lien vers la page thématique pertinente dans la même langue. Maintenant, on rencontre un petit problème: on sait quels thèmes appartiennent à une page d'article donnée, mais comme on a des pages de thème dans plusieurs langues, on ne sait pas à quels se lier. On peut résoudre ce problème en ajoutant la méthode suivante à la classe ArticlePage
:
def themepages(self):
return ThemePage.objects.filter(theme__in=self.themes.all(), language=self.language)
Cela renverra exactement toutes les pages de thème appartenant aux thèmes associés dans la même langue que la page de l'article. Maintenant, le code pour répertorier les thèmes sur la page de l'article est:
{% if page.themes.all %}
<div class="container-fluid mt-4">
{% trans "Themes:" %}
{% for themepage in page.themepages %}
<a href="{{ themepage.url }}" class="badge badge-primary">{{ themepage.theme.name }}</a>
{% endfor %}
</div>
{% endif %}
Les modèles sont finis, alors essayez-les. Migrez la base de données, accédez à l'éditeur, créez des thèmes via le menu Extraits, sélectionnez les thèmes pertinents pour vos articles, créez une page d'index pour tous vos thèmes avec le modèle de ThemeIndexPage
: tout devrait être simple, vérifiez la vidéo si vous le souhaitez.
Pour ceux d'entre vous qui veulent non seulement vos pages mais aussi vos thèmes en plusieurs langues, visitez ce tutoriel. Et toute personne qui souhaite ajouter la navigation à son site, lisez plus.
Commentez cet article (connectez-vous d'abord ou confirmez par nom et email ci-dessous)