web-dev-qa-db-fra.com

Django - Redéfinir la méthode Model.create ()?

Les Django docs listent uniquement des exemples pour remplacer save() et delete(). Cependant, j'aimerais définir un traitement supplémentaire pour mes modèles uniquement lorsqu'ils sont créés. Pour ceux qui connaissent Rails, cela équivaudrait à créer un filtre :before_create. Est-ce possible?

60
ground5hark

Remplacer __init__() entraînerait l’exécution de code chaque fois que la représentation python de l’objet est instanciée. Je ne connais pas Rails, mais un filtre :before_created me semble être du code à exécuter lorsque l'objet est créé dans la base de données. Si vous voulez exécuter du code lorsqu'un nouvel objet est créé dans la base de données, vous devez remplacer save(), en vérifiant si l'objet a un attribut pk ou non. Le code ressemblerait à ceci:

def save(self, *args, **kwargs):
    if not self.pk:
        # This code only happens if the objects is
        # not in the database yet. Otherwise it would
        # have pk
    super(MyModel, self).save(*args, **kwargs)
121
Zach

un exemple sur la façon de créer un signal post_save (from http://djangosnippets.org/snippets/500/ )

from Django.db.models.signals import post_save
from Django.dispatch import receiver

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    """Create a matching profile whenever a user object is created."""
    if created: 
        profile, new = UserProfile.objects.get_or_create(user=instance)

voici une discussion réfléchie sur le meilleur moyen d'utiliser des signaux ou des méthodes de sauvegarde personnalisées https://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/ 29/Django-signaux-vs-custom-save-method/

À mon avis, l’utilisation de signaux pour cette tâche est plus robuste, plus facile à lire mais plus longue.

20
Michael Bylstra

Ceci est vieux, a une réponse acceptée qui fonctionne (Zach), et une réponse plus idiomatique aussi (Michael Bylstra), mais comme c'est toujours le premier résultat sur Google, la plupart des gens le voient, Je pense que nous avons besoin de meilleures pratiques modernes -Django style répondre ici:

from Django.db.models.signals import post_save

class MyModel(models.Model):
    # ...
    @classmethod
    def post_create(cls, sender, instance, created, *args, **kwargs):
        if not created:
            return
        # ...what needs to happen on create

post_save.connect(MyModel.post_create, sender=MyModel)

Le point est ceci:

  1. utiliser des signaux (en savoir plus ici dans la documentation officielle )
  2. utilisez une méthode pour Nice namespacing (si cela a du sens) ... et je l'ai marquée comme @classmethod au lieu de @staticmethod car vous devrez probablement faire référence à des membres statiques de la classe dans le code

Même plus propre serait si Django de base avait un signal post_create réel. (À mon humble avis, si vous avez besoin de passer un argument booléen pour changer le comportement d'une méthode, cela devrait être 2 méthodes.)

12
NeuronQ

Remplacer __init__() vous permettra d'exécuter du code lorsque le modèle est instancié. N'oubliez pas d'appeler le __init__() du parent.

3

Vous pouvez remplacer la méthode create par un gestionnaire personnalisé ou ajouter une méthode de classe à la classe de modèle. https://docs.djangoproject.com/fr/1.11/ref/models/instances/#creating-objects

3
Ryan Allen