2

我有一个 Django 模型,它带有一个可以为“自我”的外键。我有兴趣在递归深度上引入一个硬限制(比如 10)。哪里是检查这个的合适的地方,我应该在那里抛出什么样的异常?

我的意思的伪示例:

def limit_recursion_depth(self):
    depth = 0
    model = self
    while model.parent is not None:
        depth += 1
        model = model.parent
    if depth > 10:
        pass # Complain here and stop processing
    else:
        pass # Return the model, save, whatever is normal

我对覆盖模型的 save() 方法之类的解决方案比任何仅适用于管理员的验证更感兴趣。(例如,我希望能够验证 Model.objects.create()。)

更新

尽管这个问题主要是学术性的,并且与我不再追求的项目有关,但我想更新这个问题,以防有人通过谷歌发现这个问题。以下来自django-mptt 文档

要获取所有这些页面标题,您可以执行以下操作:

titles = []
while page:
    titles.append(page.title)
    page = page.parent

这是每一页的一个数据库查询......

即使对于小型项目,Django-mptt 的效率也要高得多,即使在这种情况下,我也可能应该使用它。

4

3 回答 3

4

也许是这样的?

def save(self, *args, **kwargs):
    if Foo.objects.filter(foo=self.foo).count() > 10:
        raise Exception("not more than 10")
    else:
        super(Foo, self).save(*args, **kwargs)

更新:

对于self参考字段,django-mptt您可以执行以下操作:

def save(self, *args, **kwargs):
    if Foo.objects.filter(foo=self.foo).get_descendant_count() > 10:
        raise Exception("not more than 10")
    else:
        super(Foo, self).save(*args, **kwargs)
于 2013-08-07T04:20:37.267 回答
0

无周期版本:

    def clean_parent(self):
        parent = self.cleaned_data['parent']
        if parent and parent.level >= 10:
            raise ValidationError('Recursion Depth Exceeded')
        return parent

注意:级别从 0 开始。

于 2013-11-14T14:50:33.337 回答
-1

不幸的是,正如在这个答案中很好地解释的那样,在 Django 中确实没有一个好的方法来做到这一点。例如,每次最终用户点击更改表单上的保存按钮时,上述方法只会让管理员崩溃,并显示 500 错误——几乎没有帮助。唯一正确的方法是定义clean_{fieldname}并抛出 ValidationError。例如,它不会验证model.save()来自 的a manage.py shell,但也不会覆盖该验证,例如queryset.update().

因此,我现在采用的解决方案如下所示:

def clean_parent(self):
    depth = 0
    model = self.instance
    while model.parent is not None:
        depth += 1
        model = model.parent
    if depth > 10:
        raise ValidationError('Recursion Depth Exceeded')

请注意,这属于模型的管理表单。

于 2013-08-18T02:12:52.033 回答