Validation in a delete form
我已经创建了一个删除对象的表单,但是我需要检查要删除对象的用户是否是创建该对象的用户。我想在表单(以及视图)中检查它,因为它是一个业务约束。在init、delete或clean方法中,最好在哪里检查?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class DeleteFooForm(forms.ModelForm):
class Meta:
model = Foo
fields = []
def __init__(self, user, *args, **kwargs):
super(DeleteFooForm, self).__init__(*args, **kwargs)
self.user = user
def delete(self):
if self.user is not self.instance.user:
raise PermissionDenied("Wrong user")
self.instance.delete()
# more actions, send email, etc. |
- 在表单中,您没有访问请求对象的权限,因此它是验证权限的错误位置。在视图中执行此操作,并使用消息框架将错误闪存给用户。
- 我个人建议使用clean()方法,因为它是一个使表单无效的表单约束(在某种程度上)。
- @保罗斯卡丁,我完全不同意。表单绝对是进行验证的正确地方:这就是它的主要用途。没有理由在两个不同的地方进行验证。
- @丹尼尔罗斯曼:也许你是对的,但不幸的是你不能这么做。原因是在表单方法中,您没有关于谁登录的信息。没有这些信息,就不可能确认所有权。
- @pauloscardine i在表单构造函数中传递用户信息。
- @伊凡:是的,但我不认为这是惯用的形式。Django开发人员选择不在表单构造函数中传递整个请求对象的原因超出了我的理解范围,但很明显他们希望将关注点分开。
实际上,这应该发生在clean方法中:这是验证的地方。这样做的主要原因是您可以按照正常的方法进行验证,这是为了引发一个validationError,它将被表单API捕获并作为一个错误显示。
您当然不想在__init__中执行此操作,因为这样即使表单最初显示时也会产生错误,而且delete太晚了。
- 注意表单没有任何相关的数据,所以不会执行clean方法(除非我直接执行它)。我不显示任何内容,我只是使用一个表单来解决验证问题(CSRF和用户),因为我可以在删除对象时添加一些额外的操作。
- @Ivan:我这样做的方法是使用一个从路径(如/foo/123/delete中获取对象ID的删除URL),在get请求时,我显示一个简单的yes/no确认表单(不是modelform),如果用户选择"yes",我在post上调用foo.delete()。如果用户不是对象所有者,我将显示一条消息和一个链接,以返回而不是表单。
- 如果这是删除对象的预期方式,那么Django中将有一个ModelDeleteForm。
- @然后,您将删除该对象,并在视图(API)中执行与该命令相关的任何其他操作(验证用户、编写日志消息等),将业务逻辑与API耦合。我认为delete(作为save或update)是一个不应该在视图中实现的命令,表单是实现它的最佳位置,如这里所示。当然,这是一个意见问题。
- @伊凡:你的偏好是意见问题,它在Django中不是惯用的,这是一个可证实的事实:在Django文档中没有你的方法的单一示例,并且它没有在Django admin应用程序中使用。-)