2010-02-04 134 views
2

这让我感到莫名其妙......当我保存模型时,图书对象保持不变。但是,如果我打开发票并再次保存,则会进行更改。我究竟做错了什么?Django:在保存后访问ManyToManyField对象

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() 

编辑:我使用post_save信号试过,但它的工作方式相同。第一次保存没有变化,第二次保存更改。

更新:似乎与此代码来解决:

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

我会考虑重新设计。即使它按照预期工作,如果必须对发票进行更改,会发生什么情况?当你保存它时,它会看起来像书被卖了两次。 – 2010-02-05 00:28:07

+0

是的,这是真的:我的研究的第二部分是跟踪instance_id以查看是否已保存...我认为从Django 1.2开始m2m_changed可能正是我所需要的... – tufelkinder 2010-02-05 14:49:57

回答

4

这就是我如何解决这个问题,确实令人困惑的行为。将信号接收器连接到models.signals.m2m_changed事件,每次更改m2m字段时都触发此get。内联评论解释了原因。

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

那是因为你的模型保存后M2M关系被保存,以便获得父对象的PK。在你的情况下,第二次保存按预期工作,因为模型已经有PK和第一次保存的相关书籍(它是在一个信号中完成的)。

我还没有找到解决方案,最好的办法是做你的改变in admin view,我猜。

+0

我知道它们在模型保存,这就是为什么我把for子句放在super()之后的原因。save()是否在post_save信号后保存?是否有信号表明他们何时被保存? – tufelkinder 2010-02-04 14:28:00

+0

它们在Invoice.save()调用后保存,所以即使您在父保存之后将其保存也不会获得m2m保存。至于信号看m2m_saved – 2010-02-04 14:42:26

+0

但我想知道什么函数被称为保存后保存m2m字段?我不能重写该字段吗? – tufelkinder 2010-02-05 06:34:35

相关问题