在Django Admin上使用自定义save()方法保存模型后返回错误消息

时间:2014-05-21 15:50:07

标签: django django-admin

我有两个型号。一个是Subscriber,在节省时间我根据已经分配给该池的订户数量分配一个池:

class Subscriber(models.Model):
    pool = models.ForeignKey(Pool)
    interface = models.CharField(max_length=30)


class Pool(models.Model):
    name = models.CharField(max_length=50)

假设只有4个Subscribers可以分配给一个池。这就是为什么我要覆盖Subscriber的save()方法:

def save(self, *args, **kwargs):
    if not self.pk:
        #Look for a free Pool among the available ones
        for pool in Pool.objects.all():
            if pool.subscriber_set.count() < 4:
                self.pool = pool
                print "Assigned pool: %s" % pool.name
                super(Subscriber, self).save(*args, **kwargs)

在我用完游泳池之前它一直很好用(所有这些游戏都分配了4个用户)。我应该如何从Django管理员处理这个?理想情况下,我想向用户显示一些错误消息,以便他可以创建更多池。

我宁愿不将池分配代码移动到表单的clean()方法,因为可能还会从不同的界面创建用户,而不是管理GUI。

有什么想法吗?

非常感谢!

1 个答案:

答案 0 :(得分:6)

我建议在clean()save()进行验证。前者会在管理员中为您提供一个很好的错误消息和工作流,而后者将确保save()本身会给出错误消息,无论您是如何创建实例的。

首先验证:

class Subscriber(models.Model):

    def clean(self)
        if not self.pk:
            if not Pool.objects.annotate(num_subscribers=Count('subscriber'))
                               .filter(num_subscribers__lt=4)
                               .exists():
                raise ValidationError('The pools are all full.')

这将从管理员自动调用(请参阅ModelForm validation上的文档)。或者 - 如果您没有清除ModelForm验证之外的内容 - 您可以使用表单的clean()方法提供此逻辑。

然后在save()方法中执行相同的操作。

    def save(self, *args, **kwargs):
        if not self.pk:
            try:
                self.pool = Pool.objects.annotate(num_subscribers=Count('subscriber'))
                                        .filter(num_subscribers__lt=4)[0]
                super(Subscriber, self).save(*args, **kwargs)
            except IndexError:
                raise ValidationError(..)

您可以在self.full_clean()内调用save()进行验证,但此版本似乎更直接(并且效率更高)。