使用save方法扩展M2M关系

时间:2016-08-21 13:55:13

标签: python django python-2.7 django-models

我有这样的模型

class Authority(models.Model):
    name=models.CharField(max_length=100)
    country=models.ForeignKey(Country)
    category=models.ForeignKey(Category)
    competitors=models.ManyToManyField("self",related_name="competitors")

我希望拥有相同国家和类别的权威机构能够自动提供M2M关系,所以我这样做了

def save(self,*args,**kwargs):
    z=Authority.objects.filter(country=self.country).filter(category=self.category)
    this_authority=Authority.objects.get(id=self.id)
    for a in z:
        this_authority.competitors.add(a)
    super(Authority,self).save(*args,**kwargs)

它没有工作,没有带来任何错误,我也在下面试试

def save(self,*args,**kwargs):
        z=Authority.objects.filter(country=self.country).filter(category=self.category)
        this_authority=Authority.objects.get(id=self.id)
        self.competitors=z
        super(Authority,self).save(*args,**kwargs)

我的代码可能出现什么问题?提前致谢。

1 个答案:

答案 0 :(得分:0)

这不符合您的预期的原因是因为Django如何处理在数据库中创建m2m关系。长话故事非常简短,当您将类似新Authority的内容保存到数据库时,Django首先编写新对象然后返回并为该新对象写入m2m关系。因此,在自定义save方法中对m2​​m关系执行任何有用的操作都很困难。

post-save signal可以在这里解决问题。 kwargs['created'] = True如果我们正在创建一个新对象,kwargs['instance']是保存从信号接收器发出的实例。

@receiver(post_save, sender = Authority)
def update_m2m_relationships(sender, **kwargs):
    if kwargs['created']: #only fire when creating new objects
        competitors_to_add = Authority.objects.filter(
                                country = kwargs['instance'].country, 
                                category = kwargs['instance'].category
                                )
        for c in competitors_to_add:
            c.competitors.add(kwargs['instance'])
            c.save() #not creating a new object; this receiver does not fire here
            kwargs['instance'].competitors.add(c)
        #all competitors have been added to the instance's m2m field
        kwargs['instance'].save()

在创建新对象时仅启动此项非常重要。如果您不包含该限制,那么当您更新for循环中的其他对象时,接收器将触发自身。

我没有对此进行过测试,但我认为它会起作用。如果没有,请告诉我,我会尽力帮助。