无论数据源如何,使用 Django/Django Rest Framework 验证和保存数据的正确过程是什么?

2024-01-21

我有一个特定的模型,我想对其执行自定义验证。我想保证在创建新实例时始终存在至少一个标识符字段,这样就不可能在没有这些字段之一的情况下创建实例,尽管没有特别需要单独的字段。

from django.db import models

class Security(models.Model):
    symbol = models.CharField(unique=True, blank=True)
    sedol = models.CharField(unique=True, blank=True)
    tradingitemid = models.Charfield(unique=True, blank=True)

我想要一种干净、可靠的方法来执行此操作,无论原始数据来自何处(例如,API 帖子或从其他来源(如 .csv 文件)获取此数据的内部函数)。

我知道我可以覆盖 models .save() 方法并执行验证,但最佳实践已说明here https://stackoverflow.com/questions/8771029/raise-a-validation-error-in-a-models-save-method-in-django建议在 .save() 方法中引发验证错误是一个坏主意,因为视图只会返回 500 响应,而不是向 post 请求返回验证错误。

我知道我可以定义一个自定义序列化器验证器 http://www.django-rest-framework.org/api-guide/validators/使用 Django Rest Framework 来验证数据的模型(这对于创建对象的 ModelViewSet 来说是一个很好的解决方案,我可以保证每次都会使用这个序列化器)。但是,这种数据完整性保证仅在该 API 端点上有效,并且开发人员每次在代码库中的其他位置创建对象时都记得使用该序列化器(对象可以在整个代码库中从除网络 API)。

我也熟悉Django的.clean() 和 .full_clean() 方法 https://docs.djangoproject.com/en/2.0/ref/models/instances/#validating-objects。这些看起来像是完美的解决方案,只不过它再次依赖于开发人员始终记得调用这些方法——这取决于开发人员的记忆力。我知道使用 ModelForm 时会自动调用这些方法,但同样,对于我的用例模型也可以从 .csv 下载创建 - 我需要一个通用的保证,这是最佳实践。我可以将 .clean() 放入模型的 .save() 方法中,但是这个answer https://stackoverflow.com/questions/4441539/why-doesnt-djangos-model-save-call-full-clean(以及帖子中的相关评论和链接)似乎使这种方法引起争议,并且可能是一种反模式。

有没有一种干净、直接的方法来保证这个模型永远不会在没有以下三个字段之一的情况下被保存:1.不会通过视图引发 500 个错误,2.不依赖于开发人员显式使用创建对象时在整个代码库中正确的序列化程序,以及 3. 不依赖于将对 .clean() 的调用侵入到模型的 .save() 方法中(看似反模式)?我觉得这里必须有一个干净的解决方案,它不是将一些验证放入序列化器中的大杂烩,一些验证放在 .clean() 方法中,黑客 .save() 方法来调用 .clean() (它会通过 ModelForms 的保存被调用两次),等等...


人们当然可以想象一种设计save()为您履行双重职责并处理验证。由于各种原因(部分总结在链接中)here https://stackoverflow.com/a/4441740/2395796),Django 决定将此过程分为两步。所以我同意你发现的共识,试图将验证硬塞到Model.save()是一种反模式。它与 Django 的设计背道而驰,并且可能会在以后引起问题。

您已经找到了“完美的解决方案”,那就是使用Model.full_clean()进行验证。我不同意你的观点,记住这一点会给开发人员带来负担。我的意思是,记住做正确的事情可能很困难,尤其是对于一个庞大而强大的框架,但这个特殊的事情很简单,有很好的文档记录,并且是 Django 的 ORM 设计的基础。

当你考虑什么是时尤其如此事实上,事实证明对开发人员来说很困难,这是错误处理本身。这不是开发商能做的model.validate_and_save()。相反,他们必须这样做:

try:
    model.validate_and_save()
except ValidationError:
    # handle error - this is the hard part

而 Django 的习语是:

try:
    model.full_clean()
except ValidationError:
    # handle error - this is the hard part
else:
    model.save()

我不认为 Django 的版本更难。 (也就是说,没有什么可以阻止你编写自己的validate_and_save方便方法。)

最后,我建议也根据您的要求添加数据库约束。这就是当您添加一个它知道如何在数据库级别强制执行的约束时 Django 所做的事情。例如,当您使用unique=True在字段上,Django 将创建数据库约束并添加 Python 代码来验证该要求。但是如果你想创建一个 Django 不知道的约束,你可以自己做同样的事情。你只需写一个Migration除了编写您自己的 Python 版本之外,它还创建适当的数据库约束clean()。这样,如果您的代码中存在错误并且验证未完成,您最终会遇到未捕获的异常(IntegrityError)而不是损坏的数据。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无论数据源如何,使用 Django/Django Rest Framework 验证和保存数据的正确过程是什么? 的相关文章

  • 使用组合时如何解决循环依赖?

    我遇到了如下所示的情况 其中每个类都需要另一个类 并且它创建了循环依赖关系 我在使用 ctypes 包装一些 C 代码时遇到了这种情况 已经有很多关于这个主题的帖子 但我发现它们没有帮助 我需要一些例子 Module A from B im
  • 为不带引号的函数获取字符串参数

    我有一个函数 用于从 URL 下载文件并将其写入磁盘 并施加特定的文件扩展名 目前 它看起来像这样 import requests import os def getpml url filename psc requests get url
  • 每当我尝试在 VPS 上使用 Discord 机器人登录时,都会收到“SSL:Certificate_verify_failed”

    我正在将我的机器人从旧的 坏掉的笔记本电脑转移到合适的 VPS 我使用的是较旧的异步版本的 Discord py 0 16 0 因为我在重写之前很长时间就开始研究这个东西了 而且我对 Linux 没有太多经验 因此迁移到 Windows S
  • ValueError:无法将 DatetimeIndex 转换为 dtype datetime64[us]

    我正在尝试为 S P 500 ETF 创建一个包含 30 分钟数据的 PostgreSQL 表 spy30new 用于测试新插入的数据 来自具有 15 分钟数据的多个股票的表 全部 15 个 all15 在 dt 时间戳 和 instr 股
  • 回归模型 statsmodel python

    这更多是一个统计问题 因为代码运行良好 但我正在学习 python 中的回归建模 我在下面使用 statsmodel 编写了一些代码来创建一个简单的线性回归模型 import statsmodels api as sm import num
  • 根据另一个非索引数组中的值从 numpy 数组中选择元素

    假设我有以下两个数组 a array 1 L 74 423088306605 5 H 128 05441039929008 2 L 68 0581377353869 0 H 88 15726964130869 4 L 97 45015825
  • 确定列的累积最大值

    我正在尝试以下代码 df pd DataFrame 23 52 36 49 52 61 75 82 97 12 columns A B df C np where df A gt df C shift df A df C shift pri
  • Groupby Sum 忽略几列

    在此数据框中 我想按 位置 进行分组并获得 分数 的总和 但我不希望 纬度 经度 和 年份 在此过程中受到影响 sample pd DataFrame Location A B C A B C Year 2001 2002 2003 200
  • 如何在 django-crispy-forms 中将表单字段分布在两列布局上?

    我收到了一些使用 django crispy forms 在 Django 中创建表单的建议 我已经在文档中寻找了几个小时 但无法找出如何将表单字段分布在两列上的方法 看这个例子here https gist github com 1838
  • django PermissionRequiredMixin Permission_required 不起作用

    Views py class templateList PermissionRequiredMixin TemplateView permission required accounts template all def get self
  • 使用字典时如何避免 KeyError?

    现在我正在尝试编写汇编程序 但我不断收到此错误 Traceback most recent call last File Users Douglas Documents NeWS py line 44 in if item in regis
  • 使用 python 更改目录

    我碰巧发现我无法从 python 代码中更改实际目录 我的测试程序如下 from os import system def sh script system bash c s script sh cd home sh pwd 的输出pwd
  • 如何检测斑点并将其裁剪成 png 文件?

    我一直在开发一个网络应用程序 我陷入了一个有问题的问题 我会尝试解释我想要做什么 在这里您看到第一个大图像 其中有绿色形状 我想要做的是将这些形状裁剪成不同的 png 文件 并使它们的背景透明 就像大图像下面的示例裁剪图像一样 第一张图像将
  • python中的unicode错误[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 在下面的代码中我收到错误mailSe
  • 使用Python构建caffe(找不到-lboost_python3)

    我正在尝试用 python 构建 caffe 但它一直这样说 CXX LD o python caffe caffe so python caffe caffe cpp usr bin ld cannot find lboost pytho
  • Django ImageField 默认值

    模型 py class UserProfile models Model photo models ImageField upload to get upload file name storage OverwriteStorage def
  • 如何从 Django 中的链接设置预定义的表单值?

    我的项目是这样布局的 1 page has many categories 2 category belongs to page has many items 3 item belongs to category 当我进入一个页面时 我想修
  • pandas - 组合行的字符串

    我有一个像这样的数据框 id text 1 DM HTN Enlarged prostate 2 hypertensive and on regular treatment 2 LBP 3 DM HTN Enlarged prostate
  • Python 单元测试:Nose 失败时重试?

    我有一个随机失败的测试 我想让它在发送错误消息之前重试多次 我将 python 与 Nose 一起使用 我写了以下内容 但不幸的是 即使使用 try except 处理 当第一次尝试测试失败时 Nose 也会返回错误 def test so
  • python 根据日期创建目录结构

    我使用以下函数根据今天的日期创建目录 usr bin python import time datetime os today datetime date today todaystr today isoformat os mkdir to

随机推荐