• 12 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 22/03/2024

Manipulez des objets en surchargeant des méthodes de modèle

É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 champword_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_countconstitue la bonne façon d’accéder au nombre de mots.

  • Mettre à jour la méthodesave()pour assigner àword_countle 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.

Exemple de certificat de réussite
Exemple de certificat de réussite