Surcharger la méthode save Django
Re,
Il y a peut-être une chose que j'ai mal comprise.
La fonction super est utilisée après ma condition.
Mais est-ce que j'aurais pu coder ma condition après super() ?
Car dans la formation de base Python on utilisait toujours super() en premier.
Au passage, il faut avoir en paramètre args et kwargs.
Args car on peut avoir plusieurs paramètres ? Et kwargs car on peut avoir une clé=valeur en paramètre ?
Merci d'avance
from django.db import models
from django.utils.text import slugify
# Create your models here.
class BlogPost(models.Model):
# pour CharField il faut absolument définir une longueur en param
title = models.CharField(max_length=100)
# pour transformer title en url on utilise un slug
slug = models.SlugField(blank=True)
# valeur par défaut en param
published = models.BooleanField(default=False)
# blank permet de spécifier que je peux laisser vide. Sinon obligé de renseigner date
date = models.DateField(blank=True, null=True)
content = models.TextField()
description = models.TextField()
# une info que je ne veux pas forcémment stocker dans ma BDD mais juste afficher ==>
def publish_string(self):
if self.published:
return "L'article est publié"
return "L'article est inaccessible"
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
Salut Gabriel,
Tout dépend de ce que tu souhaites faire :)
Si tu utilises super en premier, tu vas faire le processus de sauvegarde de Django en premier et ton processus par la suite.
Ça dépend donc pas mal des cas d'usage. Parfois on a besoin que Django fasse déjà la sauvegarde pour ensuite faire une opération spécifique qui n'est possible qu'après, parfois l'inverse.
Pour les args et kwargs oui c'est ça, ça t'assure par exemple si tu passes des paramètres nommés ou non-nommés qu'ils soient bien transmis à Django.
La méthode save de Django accepte plusieurs paramètres si tu vas voir dans la documentation :
Model.save(force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)
Donc imagine que tu sauvegardes ton blog post et que tu souhaites spécifier force_insert = True.
Si tu ne passes pas les args et kwargs dans super, le paramètre ne sera pas passé à Django quand il fait la sauvegarde (quand tu appelles super().save).
C'est donc bien important de mettre les *args et **kwargs dans la définition de ta fonction afin de pouvoir les passer quand tu utilises la fonction save.
Sinon Django te diras que les paramètres n'existent pas, exactement comme si tu faisais :
>>> def foo():
... pass
...
>>> foo(a=5)
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/code.py", line 90, in runcode
exec(code, self.locals)
File "<console>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'a'
Et de la même façon, bien important de les passer à save quand tu fais super().save(*args, **kwargs) sinon ils ne seront pas passés à la méthode save du parent (models.Model).
Je ne sais pas si c'est bien clair, on est vraiment dans le coeur de l'orienté objet là donc c'est des concepts assez avancés, mais il faut bien comprendre la différence ici entre la définition de la fonction, et l'utilisation de la fonction avec super.
Dans la définition de la fonction, *args et **kwargs permettent d'accepter n'importe quel argument nommé (kwargs) ou non-nommé (args), et ensuite dans le super().save(*args, **kwargs) on passe ces arguments nommés et non-nommés "le long de la chaîne".
On pourrait aussi les indiquer explicitement, mais ça serait assez pénible de devoir à chaque fois aller regarder dans la doc quels sont les paramètres à indiquer.
Également, tu devrais synchroniser ces paramètres à chaque changement de Django (imagine que dans la prochaine version de Django ils rajoutent un paramètre à la méthode save, tu devrais tenir compte de tous ces changements et mettre à jour tes propres méthodes : la galère !).
Mais c'est probablement plus clair si tu le visualise comme ça :
def save(self, force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None):
if not self.slug:
self.slug = slugify(self.title)
super().save(force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
Bonne continuation !
Inscris-toi
(c'est gratuit !)
Tu dois créer un compte pour participer aux discussions.
Créer un compte