Écrivez vos propres méthodes de modèle pour redimensionner des photos
L’un des patrons de conception, ou design patterns, couramment utilisé dans les applications Django s’appelle « fat models — skinny views » (littéralement : gros modèles — vues maigres). Sa philosophie : la logique de vos vues doit être aussi simple que possible, et le gros du travail doit être effectué par les modèles.
Vous pouvez y parvenir en écrivant des méthodes personnalisées pour vos modèles. Elles rendent vos vues plus simples et plus lisibles. Vous pouvez donc facilement réutiliser la logique de votre méthode pour différentes vues ou tâches.
Quelle logique appartient à une méthode de modèle ?
Si le code que vous écrivez implique de manipuler un modèle ou de récupérer des informations depuis un modèle, il constitue probablement une méthode de modèle.
Pour notre projet, nous voulons redimensionner les photos avant de les sauvegarder. Cela nous aidera à éviter des coûts de stockage élevés lorsque nous aurons davantage de photos.
Comme cette méthode manipule le modèle Photo
, c’est une candidate parfaite pour être une méthode de modèle. Si nous mettions cette logique uniquement dans une vue, nous ne pourrions la réutiliser nulle part ailleurs, et cela compliquerait également la logique de la vue. Découvrez dans la vidéo ci-dessous comment concevoir vos propres méthodes de modèle :
Utilisons la bibliothèque Pillow
pour redimensionner les photos. Vous avez installé cette librairie tout à l’heure, car elle est nécessaire lorsqu’on utilise ImageField
. Vous pouvez aussi l’utiliser pour manipuler des images.
Pour redimensionner l’image tout en conservant ses proportions d’origine, utilisez la fonction thumbnail
. Elle ne redimensionnera l’image que si celle-ci est supérieure à la taille maximale.
Nous allons créer une nouvelle méthode dans notre modèle Photo
, resize_image
:
# blog/models.py
from PIL import Image
class Photo(models.Model):
...
IMAGE_MAX_SIZE = (800, 800)
def resize_image(self):
image = Image.open(self.image)
image.thumbnail(self.IMAGE_MAX_SIZE)
# sauvegarde de l’image redimensionnée dans le système de fichiers
# ce n’est pas la méthode save() du modèle !
image.save(self.image.path)
Testons-la maintenant dans le shell Python. Nous prenons une image que nous avons déjà mise en ligne, donc pour votre test, vous devrez tout d’abord charger une image via le site.
>>> from blog.models import Photo
>>> photo = Photo.objects.first()
>>> print(f'taille : {photo.image.size // 1000} ko')
taille : 683 ko
>>> photo.resize_image()
>>> print(f'taille : {photo.image.size // 1000} ko')
taille : 44 ko
On dirait que nous avons réduit la taille de la photo plus de 15 fois ! Maintenant que vous avez la capacité de redimensionner les photos, voyons comment faire en sorte que ce soit fait automatiquement, dès qu’une photo est enregistrée.
Surchargez la méthode save()
sur un modèle
Vous avez maintenant une méthode bien pratique, resize_image
, sur le modèle Photo
. Mais vous ne voulez pas avoir à appeler cette méthode manuellement à chaque fois qu’une nouvelle photo est mise en ligne !
Vous vous souvenez avoir utilisé la méthode save()
pour enregistrer des instances de modèle dans la base de données ? Eh bien, vous pouvez surcharger cette méthode. En réalité, vous pouvez surcharger toutes les méthodes des modèles pour les personnaliser selon vos besoins.
Surchargeons la méthode save()
de la classe Photo
pour nous assurer que toutes les photos mises en ligne sur le site soient redimensionnées selon vos spécifications. Voici comment en vidéo :
Voyons de quoi ça a l’air. Premièrement, utilisez la méthode super()
pour vous assurer que la sauvegarde de l’objet en base de données fonctionne toujours.
class Photo(models.Model):
...
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
Lorsque vous surchargez les modèles intégrés de Django, c’est toujours une bonne idée de récupérer les arguments *args
et **kwargs
passés à votre méthode et de les fournir à la méthode super()
, même si les spécifications actuelles ne les exigent pas.
Pourquoi ?
Car si les spécifications changent, et que la méthode de modèle commence à prendre des arguments nouveaux et différents, votre méthode personnalisée pourra les gérer, grâce aux *args
et **kwargs
génériques.
Et maintenant, ajoutez simplement la méthode resize_image()
:
class Photo(models.Model):
...
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.resize_image()
C’est aussi simple que ça ! Vos images seront désormais automatiquement redimensionnées dès que la méthode Photo.save()
sera appelée.
C'est à vous ! Écrivez des méthodes personnalisées pour le modèle Blog
Nous voulons maintenant afficher le nombre de mots du post de Blog
sur le front-end. Pour ce faire, calculez-le à partir du champ content
de Blog
.
Imaginons qu’un développeur senior ait décidé que le fait de calculer le nombre de mots pour chaque billet individuel au fil de l’eau était trop intensif d’un point de vue informatique. Il estime que ces informations devraient être stockées en tant que champ dans le modèle Blog
. Ce champ devrait alors se mettre à jour automatiquement, dès que l’on apporte des changements à l’instance de Blog
.
Vous allez devoir :
Créer un nouveau champ
word_count
sur le modèleBlog
. Vous pouvez paramétrernull=True
pour ne pas avoir à fournir une valeur par défaut.Générer et exécuter les migrations afin de mettre en œuvre ce changement.
Ajouter une nouvelle méthode
_get_word_count()
au modèleBlog
, qui calcule le nombre de mots du champcontent
. Le tiret bas (ou underscore) du début indique qu’il s’agit d’une méthode interne, et que l’attributword_count
constitue la bonne façon d’accéder au nombre de mots.Mettre à jour la méthode
save()
pour assigner àword_count
le résultat de_get_word_count()
.
Une fois que vous aurez essayé, comparez votre travail avec la solution dans le dépôt GitHub.
En résumé
Écrivez les blocs de code qui manipulent ou récupèrent des données depuis des modèles en tant que méthodes de modèle.
Lorsque c’est approprié, conservez la logique dans les modèles (fat models) et non dans les vues (skinny views).
Vous pouvez surcharger les méthodes de base d’un modèle, telles que les méthodes
save()
etdelete()
.
Maintenant que vous savez manipuler des modèles grâce aux méthodes, assurons-nous qu’il n’y a pas de perte de données lors des migrations vers de nouveaux schémas de base de données.