Utilisez des filtres personnalisés dans les gabarits
Maintenant que nos instances Photo
et Blog
sont classées dans une liste, nous pouvons les afficher dans le flux. Comment ? La réponse en vidéo.
Commençons par mettre à jour le gabarit home.html
pour itérer dans l’ensemble de la nouvelle liste des instances Photo
et Blog
:
# blog/templates/blog/home.html
{% extends 'base.html' %}
{% block content %}
<h2>Votre flux</h2>
{% for instance in photos_and_blogs %}
...
{% endfor %}
{% endblock content %}
Nous voulons afficher les Blog
et Photo
différemment. Il nous faut donc un moyen de distinguer entre les différents types d’objet dans le gabarit.
En Python pur, vous pourriez vérifier le type()
de l’objet, comme ceci :
if type(instance) is models.Blog:
# Traitement d’un billet de blog
Mais lorsque vous utilisez le langage de gabarit Django, vous n’avez pas accès aux fonctions standards de Python telles que type()
. Donc, pour récupérer le type de modèle, vous devez écrire un filtre personnalisé.
Lorsque vous créez des balises et gabarits personnalisés, spécifiez-les dans un répertoire templatetags
dans une application Django. Cela permettra à Django de les intégrer automatiquement. Vous devez également inclure un fichier __init__.py
vide, afin que le répertoire templatetags
soit considéré comme un package Python.
Ajoutons un filtre personnalisé dans un fichier nommé blog_extras.py
.
(ENV) ~/fotoblog (master)
→ mkdir blog/templatetags
(ENV) ~/fotoblog (master)
→ touch blog/templatetags/__init__.py
(ENV) ~/fotoblog (master)
→ touch blog/templatetags/blog_extras.py
Un filtre personnalisé peut prendre un ou deux arguments. Tout ce que la fonction renvoie est affiché dans le gabarit comme résultat du filtre appliqué.
Dans notre cas, nous allons utiliser le filtre pour renvoyer une représentation en chaîne de caractères du type de modèle auquel l’instance appartient. Cela nécessitera seulement de fournir un argument, l’instance.
# blog/templatetags/blog_extras.py
def model_type(instance):
return type(instance).__name__
Pour garantir l’accessibilité de ces filtres dans les gabarits, créez une instance deLibrary
que vous nommerezregister
et enregistrez-y les filtres avec le décorateur@register.filter
.
# blog/templatetags/blog_extras.py
from django import template
register = template.Library()
@register.filter
def model_type(value):
return type(value).__name__
À présent que vous avez le filtre, vous pouvez l’utiliser pour distinguer les types d’objets dans le gabarit.
Utilisez la syntaxe suivante pour utiliser le filtre :
{{ instance|model_type }}
Elle donnera comme résultat soit 'Blog'
, soit 'Photo'
.
Nous voulons utiliser ce résultat dans une instruction if
, pour déterminer s’il faut afficher une photo ou un billet de blog. Avec le langage de gabarit de Django, on peut créer des instructions conditionnelles avec la balise {% if <condition> %}
. Vous pouvez également utiliser nos filtres dans cette balise.
Pour utiliser notre balise personnalisée dans un gabarit, nous devons la charger dans le contexte du gabarit avec la balise{% load %}
. Dans notre cas, nous ajoutons{% load blog_extras %}
.
Pour utiliser la balise dans le gabarit de la page d’accueil, ajoutez :
{% extends 'base.html' %}
{% load blog_extras %}
{% block content %}
<h2>Votre flux</h2>
<div class="grid-container">
{% for instance in blogs_and_photos %}
{% if instance|model_type == 'Blog' %}
// Billet affiché ici
{% elif instance|model_type == 'Photo' %}
// Photo affichée ici
{% endif %}
{% endfor %}
</div>
{% endblock content %}
Ajoutez le HTML nécessaire pour afficher les billets de blog et les photos :
{% extends 'base.html' %}
{% load blog_extras %}
{% block content %}
<h2>Votre flux</h2>
<div class="grid-container">
{% for instance in blogs_and_photos %}
{% if instance|model_type == 'Blog' %}
<div class="post">
<a href="{% url 'view_blog' instance.id %}">
<h4>Billet : {{ instance.title }}</h4>
<img src="{{ instance.photo.image.url }}">
<p><strong>Écrit par {{ instance.contributors.all|join:", " }}</strong></p>
<p>{{ instance.date_created }}</p>
</a>
</div>
{% elif instance|model_type == 'Photo' %}
<div class="post">
<img src="{{ instance.image.url }}">
<p>{{ instance.caption }}</p>
<p><strong>Prise par {{ instance.uploader }}</strong></p>
<p>{{ instance.date_created }}</p>
</div>
{% endif %}
{% endfor %}
</div>
{% endblock content %}
Voyons à quoi ça ressemble dans le navigateur !
Il a l’air bien, même s’il y a quelques trucs que l’on peut améliorer. Regardons-les maintenant !
Utilisez des balises personnalisées dans les gabarits
Pour l’instant, le nom d’utilisateur de chaque personne effectuant un téléversement (les « uploaders ») se trouve à côté de chaque photo. C’est acceptable, mais nous voulons un affichage plus dynamique ! La solution en vidéo :
Au lieu de voir « Prise par <votre-username> », ce serait agréable de voir « Prise par vous. »
Pour faire ce changement, utilisez une balise personnalisée.
Les balises personnalisées sont similaires aux filtres personnalisés, mais elles utilisent la syntaxe {% %}
.
Accédons au contexte du gabarit dans notre balise personnalisée, et utilisons-le pour afficher soit « vous », soit le nom d’utilisateur de la personne qui a posté, en fonction de qui est connecté.
Pour enregistrer une fonction en tant que balise personnalisée, utilisez le décorateur @register.simple_tag
. Pour inclure le contexte du gabarit dans la balise, passez l’argument takes_context=True
. En ajoutant ce flag, le premier argument de la fonction de la balise doit être nommé « context ».
Écrivons une balise personnalisée. Tout ce que la balise renverra sera affiché dans le gabarit lorsque nous l’utiliserons.
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def get_poster_display(context, user):
if user == context['user']:
return 'vous'
return user.username
Et maintenant, incorporez-la dans la vue :
{% extends 'base.html' %}
{% load blog_extras %}
{% block content %}
<h2>Votre flux</h2>
<div class="grid-container">
{% for instance in blogs_and_photos %}
// Billet affiché ici
{% elif instance|model_type == 'Photo' %}
<div class="post">
<img src="{{ instance.image.url }}">
<p>{{ instance.caption }}</p>
<p><strong>Taken by {% get_poster_display instance.uploader %}
</strong></p>
<p>{{ instance.date_created }}</p>
</div>
{% endif %}
{% endfor %}
</div>
{% endblock content %}
Et vous pouvez regarder à quoi ça ressemble !
Ça a meilleure allure, mais le format des dates mériterait d'être amélioré. Vous allez maintenant créer votre propre filtre pour les afficher correctement.
C'est à vous ! Créez votre propre filtre personnalisé
Affichez une chaîne de façon dynamique, en fonction de la date d’ajout d’un post.
Vous allez devoir :
Créer un filtre nommé
get_posted_at_display
prenant un argument,time
.Comparer la valeur avec celle de
django.utils.timezone.now()
. Ça renvoie une date et une heure prenant en compte le fuseau horaire du serveur, et doit être utilisé surdatetime.datetime.now()
.Renvoyer une chaîne en fonction des conditions suivantes :
0 < x < 60 minutes —
'Posté il y a x minutes'
1 < x < 24 heures —
'Posté il y a x heures'
x > 24 heures —
'Posté à HH:MM jj mm aa
, par exemple17:53 04 Avr 21
. Utilisezstrftime
pour créer cette chaîne.
Utiliser votre nouveau filtre pour afficher l’heure à laquelle le billet ou la photo a été publié sur le fil d’actualité.
Lorsque vous aurez ajouté votre filtre personnalisé, comparez-le avec la solution dans le dépôt GitHub.
Maintenant que nous avons construit le fil d’actualité, nettoyons le gabarit et créons des éléments de gabarit réutilisables avec la balise {% include %}
.
Utilisez des gabarits partiels réutilisables avec la balise {% include %}
Nous avons déjà utilisé la balise {% extends %}
pour permettre à chaque gabarit du site d’être construit à partir d’un gabarit de base réutilisable.
Vous pouvez également utiliser la balise {% include %}
pour créer des éléments réutilisables, pouvant être répétés dans plusieurs gabarits.
En construisant notre flux, nous voulons afficher chaque billet de blog et chaque photo de la même manière à chaque fois. Nous voudrons aussi peut-être afficher nos billets de blog et photos dans différentes parties du site. Pour faire cela, il nous faut créer un gabarit partiel. Découvrez de quelle manière en vidéo :
Nous allons stocker nos gabarits partiels dans blog/templates/blog/partials/
.
Tout d’abord, créons un gabarit partiel pour afficher une instance deBlog
nommé blog_snippet.html
.
Créez cet extrait tout comme un gabarit normal. Vous pouvez copier le segment de gabarit de votre gabarit de flux, mais vu que vous travaillez avec une instance deBlog
, renommez instance
en blog
.
{% load blog_extras %}
<div class="post">
<a href="{% url 'view_blog' blog.id %}">
<h4>Billet : {{ blog.title }}</h4>
<img src="{{ blog.photo.image.url }}">
<p><strong>Écrit par {{ blog.contributors.all|join:", " }}</strong></p>
<p>{{ blog.date_created|get_posted_at_display }}</p>
</a>
</div>
Incluez maintenant l’extrait de blog dans le gabarit du flux, en utilisant le mot-clé with
pour renommer la variable instance
en blog
dans le gabarit partiel.
Le remplacement de la section de blog du gabarit du flux par l’extrait ressemble à ça :
{% extends 'base.html' %}
{% load blog_extras %}
{% block content %}
<h2>Votre flux</h2>
<div class="grid-container">
{% for instance in blogs_and_photos %}
{% if instance|model_type == 'Blog' %}
{% include 'blog/partials/blog_snippet.html' with blog=instance %}
{% elif instance|model_type == 'Photo' %}
...
{% endif %}
{% endfor %}
</div>
{% endblock content %}
Voyons à quoi ressemble le flux lorsqu’il utilise un extrait.
C’est exactement pareil ! Tout fonctionne comme prévu.
L’avantage d’utiliser un gabarit partiel, comme celui-ci, est que vous pouvez réutiliser cet extrait dans n’importe quel gabarit de votre site. Cela rend aussi le gabarit d’origine plus propre et plus lisible.
Vous allez ensuite faire la même chose avec la section photo. Puis, vous allez utiliser cet extrait pour créer le flux photo.
C'est à vous ! Créez un gabarit partiel pour afficher une photo
Maintenant que vous avez appris à utiliser un gabarit partiel pour afficher une instance de Blog
, à vous de jouer pour faire la même chose avec une Photo
.
Vous pouvez utiliser cet extrait dans les flux standard et photo.
Vous allez devoir :
Créer un nouveau gabarit partiel dans
blog/templates/blog/partials/photo_snippet.html
.Copier la section photo actuelle de
feed.html
àphoto_snippet.html
.Utiliser la balise
{% include %}
pour inclurephoto_snippet.html dans feed.html
.Créer le flux photo à partir de
photo_feed.html
. Réutiliserphoto_snippet.html
dans ce gabarit en utilisant la balise{% include %}
.Inclure le flux photo dans les modèles d’URL et ajouter un lien vers celui-ci dans la barre latérale.
Une fois que vous aurez fini, vous pourrez comparer votre code avec la solution dans le dépôt GitHub.
En résumé
Créez et enregistrez des filtres et des balises personnalisés pour créer des fonctions utilitaires que vous pourrez utiliser dans les gabarits, présentant les objets et attributs de façon répétable.
Utilisez la balise
{% include %}
pour créer des éléments réutilisables dans vos gabarits.
Maintenant que vous avez affiché tous les billets et photos dans le flux, voyons comment améliorer la performance et la facilité d’utilisation de la page grâce à la pagination.