Django模型重写保存函数未更新m2m字段的数据库

0 投票
1 回答
552 浏览
提问于 2025-04-18 03:05

当我从管理面板添加一个新的横幅时,我想在创建时与这个横幅关联的关键词并没有被添加到数据库里。

class Banners(models.Model):
    objects = BannerManager()
    banner_location = models.ManyToManyField(BannerLocation, verbose_name=_("Banner's Location"), default=None, null=True, blank=True)
    keywords = models.ManyToManyField(Keywords, verbose_name=_("Banner's Related Keywords"), null=True, blank=True)
    width = models.IntegerField(verbose_name=_("Banner Width"), null=False, blank=False)
    height = models.IntegerField(verbose_name=_("Banner Height"), null=False, blank=False)
    invocation_code = models.TextField(verbose_name=_("Banner Height"), null=False, blank=False)
    is_enable = models.BooleanField(verbose_name=_("Is Enable"), default=False)
    banner_updated = models.DateTimeField(auto_now=True)
    banner_created = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "Banner"
        verbose_name_plural = "Banners"
        ordering = ['-banner_updated', 'is_enable']

    def __unicode__(self):
        return "width: %s, height: %s" % (self.width, self.height)

    def save(self):
        is_new = False
        if self.pk is None:
            is_new = True
        super(Banners, self).save()
        if is_new == True:
            keyword = Keywords.objects.get(pk=1)
            self.keywords.add(keyword)

1 个回答

1

如果你的管理表单里有一个 keywords 字段,发生的事情是这样的:

  1. 你在管理后台点击保存你的新 Banners 实例(没有选择任何关键词)
  2. Django 的管理模型表单会保存这个 Banners 实例
  3. 你重写的 save 方法会添加你的关键词
  4. Django 管理后台会把关键词的多对多字段设置为表单中提交的关键词(这会覆盖你在保存方法中设置的内容)

Django 之所以这样做,是因为你知道的,Banners 实例必须先保存,才能添加多对多关系。

我自己以前也在这方面绕了很多圈,玩弄 m2m_changed 信号等等……但你可能最终得到的东西只是在 Django 管理网站的某些特定情况下有效,而在其他代码中就不太合理了。

我觉得你的保存方法是有效的(可以在控制台中尝试,离开 Django 管理后台),你真正需要的是自定义管理表单的行为:

class BannersForm(forms.ModelForm):
    class Meta:
        model = Banners

    def __init__(self, *args, **kwargs):
        if kwargs.get('instance') is None:
            # create new Banners
            initial = kwargs.get('initial', {})
            initial.update({'keywords': Keywords.objects.filter(pk=1)})
            kwargs['initial'] = initial
        super(BannersForm, self).__init__(*args, **kwargs)


class BannersAdmin(admin.ModelAdmin):
    form = BannersForm


admin.site.register(Banners, BannersAdmin)

撰写回答