2010-02-04 7 views
2

Cela me déroute ... Lorsque je sauvegarde mon modèle, les objets du livre restent inchangés. Mais si j'ouvre la facture et la sauvegarde à nouveau, les changements sont faits. Qu'est-ce que je fais mal?Django: accéder aux objets ManyToManyField après la sauvegarde

class Invoice(models.Model): 
    ... 
    books = models.ManyToManyField(Book,blank=True,null=True) 
    ... 

    def save(self, *args, **kwargs): 
     super(Invoice, self).save(*args, **kwargs) 
     for book in self.books.all(): 
      book.quantity -= 1 
      if book.quantity == 0: 
       book.sold = True; 
      book.save() 

Edit: J'ai essayé d'utiliser le signal de post_save, mais il fonctionne de la même manière. Aucun changement lors de la première sauvegarde, modifications enregistrées la deuxième fois.

Mise à jour: semble être résolu avec ce code:

class InvoiceAdmin(admin.ModelAdmin): 
    ... 

    def save_model(self, request, obj, form, change): 
     obj.save() 
     for bk in form.cleaned_data['books']: 
      book = Book.objects.get(pk=bk.id) 
      book.quantity -= 1 
      if book.quantity == 0: 
       book.sold = True; 
      book.save() 
+0

Je penserais à la refonte. même si cela fonctionnait comme prévu, que se passerait-il si des modifications devaient être apportées à la facture? quand vous l'avez sauvé, il semblerait que les livres ont été vendus deux fois. –

+0

Oui, c'est vrai: une deuxième partie de mes recherches consiste à suivre l'instance_id pour voir si elle a déjà été sauvegardée ... Je pense que m2m_changed de Django 1.2 pourrait être exactement ce dont j'ai besoin ... – tufelkinder

Répondre

4

C'est ainsi que j'ai travaillé autour de ce comportement, voire d'un comportement déroutant. Connectez un récepteur de signal à l'événement models.signals.m2m_changed, ce get est déclenché chaque fois qu'un champ m2m est modifié. Les commentaires en ligne expliquent pourquoi.

class Gig(models.Model): 
    def slugify(self): 
     # Add venue name, date and artists to slug 
     self.slug = slugify(self.venue.name) + "-" 
     self.slug += self.date.strftime("%d-%m-%Y") + "-" 
     self.slug += "-".join([slugify(artist.name) for artist in self.artists.all()]) 
     self.save() 


@receiver(models.signals.m2m_changed, sender=Gig.artist.through) 
def gig_artists_changed(sender, instance, **kwargs): 
    # This callback function get's called twice. 
    # 1 first change appears to be adding an empty list 
    # 2nd change is adding the actual artists 
    if instance.artist.all() and not instance.slug:                                        
     instance.slugify() 
1

En effet, par rapport m2m sont sauvegardés après votre enregistrement modèle, afin d'obtenir PK d'objet parent. Dans votre cas, la deuxième sauvegarde fonctionne comme prévu car le modèle a déjà PK et les livres associés du premier enregistrement (c'est fait dans un signal).

Je n'ai pas encore trouvé la solution, le meilleur pari est de faire vos changements in admin view, je suppose.

+0

Je sais qu'ils sont sauvegardés après la sauvegarde du modèle, c'est pourquoi je mets la clause for après super(). save() Sont-ils sauvegardés après le signal post_save? Y a-t-il un signal pour quand ils sont sauvés? – tufelkinder

+0

ils sont sauvegardés après l'appel de Invoice.save() donc même si vous mettez après le parent enregistrer, il ne sera pas enregistré m2m. En ce qui concerne les signaux, regardez m2m_saved –

+0

Mais je me demande quelle fonction est appelée après enregistrement pour enregistrer les champs m2m? Je ne pouvais pas remplacer ce champ à la place? – tufelkinder

Questions connexes