我有一个Django模型,其中可自由的ForeignKey为'self'。我有兴趣在递归深度上引入硬限制(比如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()。)
即使这个问题主要是学术性的,并且与我不再追求的项目相关,但我想更新此问题,万一有人通过Google发现这个问题。以下内容来自django-mptt documentation:
要获取所有这些页面标题,您可以执行以下操作:
titles = [] while page: titles.append(page.title) page = page.parent
这是每个页面的一个数据库查询 ...
即使对于小型项目,Django-mptt也更有效率,即使在这种情况下我也应该使用它。
答案 0 :(得分: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
的{{1}}引用字段,您可以执行以下操作:
django-mptt
答案 1 :(得分:0)
没有周期的版本:
def clean_parent(self):
parent = self.cleaned_data['parent']
if parent and parent.level >= 10:
raise ValidationError('Recursion Depth Exceeded')
return parent
注意:等级从0开始。
答案 2 :(得分:-1)
不幸的是,正如在this answer中所解释的那样,并非是在Django中执行此操作的好方法。例如,每当最终用户点击更改表单上的保存按钮时,上面的方法只会使管理员崩溃500 - 几乎没有帮助。唯一正确的方法是define clean_{fieldname}
and throw a ValidationError。例如,它不会验证model.save()
中的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')
请注意,这属于模型的管理表单。