【问题标题】:Separation of ORM and validationORM 和验证的分离
【发布时间】:2010-11-09 16:29:00
【问题描述】:

我使用 django,我想知道应该在什么情况下进行模型验证。至少有两种变体:

  1. 在模型的保存方法中进行验证,如果违反业务规则则引发 IntegrityError 或其他异常
  2. 使用表单和内置 clean_* 工具验证数据

从一个角度来看,答案是显而易见的:应该使用基于表单的验证。这是因为 ORM 是 ORM,而验证完全是另一个概念。看一下 CharField:forms.CharField 允许指定 min_length,但 models.CharField 不允许。 好的很酷,但是 django.db.models 中的所有验证功能到底在做什么?我可以指定 CharField 不能为空,我可以使用在此处执行的 EmailField、FileField、SlugField 验证,在 python 中,而不是在 RDBMS 上。此外,还有一个 URLField 可以检查 url 的 存在性,这涉及到一些非常复杂的逻辑。

另一方面,如果我有一个实体,我想保证它不会以不一致的状态保存,无论它来自表单还是由某些内部算法修改/创建。我有一个带有名称字段的模型,我希望它应该比一个字符长。我也有一个 min_age 和一个 max_age 字段,如果 min_age > max_age 没有多大意义。那么我应该在保存方法中检查这些条件吗?

模型验证的最佳实践是什么?

【问题讨论】:

    标签: python django validation architecture django-models


    【解决方案1】:

    数据库/模型验证

    数据库中的数据存储必须始终处于某种形式/状态。例如:必需的名字、姓氏、外键、唯一约束。这是您的应用程序逻辑所在的位置。无论您认为数据来自何处 - 都应在此处“验证”,如果不满足要求则引发异常。

    表单验证

    输入的数据应该看起来正确。如果通过其他方式(通过管理员或 api 调用)以不同方式输入此数据,则可以。 示例:人名的长度、句子的正确大小写...

    示例 1:对象具有 StartDateEndDateStartDate 必须始终在 EndDate 之前。你在哪里验证这个?当然是在模型中!考虑一下您可能从其他系统导入数据的情况 - 您不希望这样做。

    示例2:密码确认。您有一个用于在数据库中存储密码的字段。但是,您会在表单上显示两个字段:password1 和 password2。表单,并且只有表单,负责比较这两个字段以查看它们是否相同。表单有效后,您可以安全地将 password1 字段作为密码存储到数据库中。

    【讨论】:

      【解决方案2】:

      有一个正在进行的 Google Summer of Code 项目,旨在为 Django 模型层带来验证。您可以在 GSoC 学生 (Honza Kral) 的 this presentation 中了解更多相关信息。还有一个带有初步代码的github repository

      在该代码进入 Django 版本之前,一种推荐的方法是使用 ModelForms 来验证数据,即使源不是表单。它在 Django 核心开发人员之一的 this blog entry 中进行了描述。

      【讨论】:

        【解决方案3】:

        “但是 django.db.models 中的所有验证功能到底在做什么?”

        一个词:遗产。早期版本的 Django 表单的健壮性较差,验证分散。

        “那么我应该在保存方法中检查这些条件吗?”

        不,您应该使用表单进行所有验证。

        “模型验证的最佳实践是什么?”*

        使用表单进行所有验证。

        “是来自表单还是被某些内部算法修改/创建”

        什么?如果您的算法患有精神病发作或您的程序员是反社会者,那么 - 也许 - 您必须验证内部生成的数据。

        否则,根据定义,内部生成的数据是有效的。只有用户数据可以是无效的。如果您不信任您的软件,那么编写它的意义何在?你的单元测试被破坏了吗?

        【讨论】:

        • 这是一个非常理想化的假设。我经常不得不使用原始创建者对数据验证的方法不够严格的数据源。在将数据放入我的数据库之前,我仍然必须验证它们,即使它们不是直接来自表单。这就是为什么我如此渴望模型验证 GSoC 项目的结果:-)
        • @piquadrat:您说的是外部数据——实际上来自用户。是的,它来自数据库,但它在您的应用程序之外。这不是您的应用程序生成的内部数据。
        • @S.Lott:是的,没错。但由于数据并非来自 Web 表单,因此通过表单验证数据似乎很笨拙。一旦模型验证进入 Django 主干,它有望使这种滥用变得不必要。我想我想说的是除了网络表单之外还有其他错误数据来源......
        • @piquadrat:不同意。表格用于验证。用于验证来自其他来源的数据的 API 非常非常好。一直使用它。
        【解决方案4】:

        你的两个选项是两个不同的东西。

        • 基于表单的验证可以看作是语法验证+将HTTP请求参数从文本转换为Python类型。
        • 基于模型的验证可以视为语义验证,有时使用 HTTP/form 层不可用的上下文。

        当然,在数据库中还有第三层强制执行约束,并且由于更新数据库的并发请求(例如唯一性约束、乐观锁定),可能无法在其他任何地方检查。

        【讨论】:

          【解决方案5】:

          我不确定这是否是最佳实践,但我倾向于在将数据推送到数据库之前验证客户端和服务器端。我知道这需要更多的努力,但这可以通过在使用前设置一些值然后维护它们来完成。

          您也可以尝试使用 **kwargs 将大小约束推送到在 put() 调用之前调用的验证函数中。

          【讨论】:

            猜你喜欢
            • 2011-03-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-28
            • 2012-02-25
            • 2012-08-27
            • 1970-01-01
            • 2016-12-31
            相关资源
            最近更新 更多