Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django模型中递归外键深度的限制_Django_Django Models - Fatal编程技术网

Django模型中递归外键深度的限制

Django模型中递归外键深度的限制,django,django-models,Django,Django Models,我有一个Django模型,其“self”的外键可以为null。我想在递归深度上引入一个硬限制(比如10)。哪里是检查这个的合适位置,我应该在那里抛出什么样的异常 我的意思的伪示例: def limit_recursion_depth(self): depth = 0 model = self while model.parent is not None: depth += 1 model = model.parent if dept

我有一个Django模型,其“self”的外键可以为null。我想在递归深度上引入一个硬限制(比如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()

更新 尽管这个问题主要是学术性的,并且与我不再从事的一个项目有关,但我想更新这个问题,以防有人通过谷歌发现这个问题。下稿摘自:

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

titles = []
while page:
    titles.append(page.title)
    page = page.parent
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)
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')
每个页面都有一个数据库查询


Django mptt即使在小项目中也更有效,即使在这种情况下,我可能也应该使用它。

也许是这样的

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)
更新:

对于带有
django mpt
self
引用字段,您可以执行以下操作:

titles = []
while page:
    titles.append(page.title)
    page = page.parent
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)
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')

不幸的是,正如在中很好地解释的,在Django中确实没有一个好的方法来做到这一点。例如,上面的方法只会在最终用户每次点击更改表单上的保存按钮时以500错误使管理员崩溃——这几乎没有什么帮助。要做到这一点,唯一正确的方法是。例如,它不会验证来自
manage.py shell的
model.save()
,但也不会覆盖该验证,例如,
queryset.update()

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

titles = []
while page:
    titles.append(page.title)
    page = page.parent
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)
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')
注意,这属于模型的管理表单。

无循环版本:

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

注意:级别从0开始。

这绝对值得一次向上投票,至少在我得到代表授予一次之后。我喜欢这个想法,因为它简单明了,没有任何明显的问题(对我来说)。如果像“实际上有一种方法可以在Django正常工作”这样的回答没有很快出现,我肯定会接受。谢谢现在我在家,有时间研究这个问题,我确实看到了一个小问题。您的if条件实际上检查的是A的父项是否有超过10个子项。我想追溯A的祖先,以确保A不会有一个伟大的(递归深度)祖父。这更有意义吗?否则,这就回答了我的问题——在哪里检查(model.save()),以及抛出什么(泛型或自定义异常)。另外,什么是
断言异常()
。是的,我错过了“自我”部分。如果你要在树上走很多路,你真的应该去看看。你说的也对,那就是应该说
raise
。对不起,我已经有一段时间没有接这个项目了,但我不得不接受你的回答。Django的admin只捕获某些异常,因此如果触发递归深度,该方法将导致所有表单崩溃,并出现500错误!因此,请在希望此功能用于的表单上重写save方法。是的,使用ValidationError。在什么情况下,将为当前根定义父级?)此示例不检查子体的深度。我不确定我是否理解您的抱怨。你是说检查另一个方向的深度吗?如果是这样的话,这很容易被修改成适合你的目的(无论如何,这不是问题的所在)。我只是想解释一下,如果需要限制节点深度,我们必须考虑所有后代的深度。假设一下。A-根(深度=0)B-另一根(深度=0)C-B中的节点(C.parent是B)(深度=1)例如,模型1中的深度限制。例如,我们打开B页编辑并将父代从“无”更改为“A”。当前验证检查B深度,它将为1和罚款,但在重建树之后,C将具有深度为2,而不是深度限制。这是为什么我在更新中建议,任何这样做的人都认真考虑使用Django MPTT。使用类似于此答案中的方法检查子代将非常昂贵,而且在性能方面根本不值得。家长如何知道他的级别