无论数据源如何,使用Django / Django Rest Framework验证和保存数据的正确过程是什么? [英] What is the proper process for validating and saving data with with Django/Django Rest Framework regardless the data source?

查看:131
本文介绍了无论数据源如何,使用Django / Django Rest Framework验证和保存数据的正确过程是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 从django.db导入模型

class Security(models.Model):
符号= models.CharField(唯一= True,blank = True)
sedol = models.CharField(unique = True,blank = True)
tradingitemid = models.Charfield(unique = True,blank = True)

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



我知道我可以覆盖模型.save()方法并执行验证,但最好惯例此处建议s在.save()方法中引发验证错误是一个坏主意,因为视图将仅返回500响应,而不是将验证错误返回至发布请求。



我知道我可以使用 validator 使用Django Rest Framework进行验证数据的模型(对于创建对象的ModelViewSet来说,这是一个很好的解决方案,我可以保证每次都使用此序列化程序)。但是,这种数据完整性保证仅在该API端点上才有效,然后与开发人员在每次在代码库中的其他位置创建对象时都要记住使用该序列化程序一样好(可以在整个代码库中从其他来源创建对象) Web API)。



我也熟悉Django的。clean()和.full_clean()方法。这些似乎是完美的解决方案,除了它再次依赖于开发人员总是记住要调用这些方法-这种保证与开发人员的记忆力一样好。我知道使用ModelForm时会自动调用这些方法,但是同样,对于我的用例模型,也可以从.csv下载中创建模型-我需要通用的最佳实践保证。我可以将.cl​​ean()放入模型的.save()方法中,但这 answer (以及帖子中的相关评论和链接)似乎使这种方法引起了争议,并且可能是一种反模式。



一种确保没有以下三个字段之一就永远无法保存该模型的简单方法:1.不会通过视图引发500个错误; 2.不依赖于开发人员在整个代码库中显式使用正确的序列化程序创建对象时;以及3.是否不依赖于将对.clean()的调用破解到模型的.save()方法中(看似反模式)?我觉得这里必须有一个干净的解决方案,不是将某些验证放入序列化程序中,将某些验证放入.clean()方法中,将.save()方法修改为调用.clean()的简单方法(从ModelForms保存两次被调用两次),等等...

解决方案

一个人肯定可以想到其中 save()承担了双重职责并为您处理了验证。由于各种原因(部分此处进行了部分总结),Django决定将此过程分为两步。因此,我同意您所发现的共识,即尝试将验证加入 Model.save()是一种反模式。



您已经找到了完美的解决方案,可以使用<$ c $。它与Django的设计背道而驰。



c> Model.full_clean()进行验证。我不同意您的观点,记住这对开发人员来说将是沉重的负担。我的意思是,记住做正确的事可能很困难,尤其是在使用一个强大的大型框架的情况下,但是这一点很简单,有据可查,并且是Django ORM设计的基础。



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

  try:
model.validate_and_save()
,除了ValidationError:
#处理错误-这是困难的部分

而Django的惯用法是:

  try:
model.full_clean()
除了ValidationError:
#处理错误-这是硬部分
其他:
model.save()

我不发现Django的版本更加困难。 (也就是说,没有什么可以阻止您编写自己的 validate_and_save 便捷方法。)



最后,我建议也为您的需求添加数据库约束。这就是Django在添加一个约束时知道的方式,该约束知道如何在数据库级别执行。例如,当您在字段上使用 unique = True 时,Django将创建数据库约束并添加Python代码以验证该要求。但是,如果您要创建Django不了解的约束,则可以自己执行相同的操作。除了在 clean()中编写自己的Python版本外,您只需编写一个 Migration 即可创建适当的数据库约束。 。这样,如果代码中存在错误,并且验证未完成,您最终将得到未捕获的异常( IntegrityError ),而不是损坏的数据。


I have a particular model that I'd like to perform custom validations on. I'd like to guarantee that at least one identifier field is always present when creating a new instance such that its impossible to create an instance without one of these fields, though no field in particular is individually required.

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)

I'd like a clean, reliable way to do this no matter where the original data is coming from (e.g., an API post or internal functions that get this data from other sources like a .csv file).

I understand that I could overwrite the models .save() method and perform validation, but best practice stated here suggests that raising validation errors in the .save() method is a bad idea because views will simply return a 500 response instead of returning a validation error to a post request.

I know that I can define a custom serializer with a validator using Django Rest Framework for this model that validates the data (this would be a great solution for a ModelViewSet where the objects are created and I can guarantee this serializer is used each time). But this data integrity guarantee is only good on that API endpoint and then as good as the developer is at remembering to use that serializer each and every time an object is created elsewhere in the codebase (objects can be created throughout the codebase from sources besides the web API).

I am also familiar with Django's .clean() and .full_clean() methods. These seem like the perfect solutions, except that it again relies upon the developer always remembering to call these methods--a guarantee that's only as good as the developer's memory. I know the methods are called automatically when using a ModelForm, but again, for my use case models can be created from .csv downloads as well--I need a general purpose guarantee that's best practice. I could put .clean() in the model's .save() method, but this answer (and related comments and links in the post) seem to make this approach controversial and perhaps an anti-pattern.

Is there a clean, straightforward way to make a guarantee that this model can never be saved without one of the three fields that 1. doesn't raise 500 errors through a view, 2. that doesn't rely upon the developer explicitly using the correct serializer throughout the codebase when creating objects, and 3. Doesn't rely upon hacking a call to .clean() into the .save() method of the model (a seeming anti-pattern)? I feel like there must be a clean solution here that isn't a hodge podge of putting some validation in a serializer, some in a .clean() method, hacking the .save() method to call .clean() (it would get called twice with saves from ModelForms), etc...

解决方案

One could certainly imagine a design where save() did double duty and handled validation for you. For various reasons (partially summarized in the links here), Django decided to make this a two-step process. So I agree with the consensus you found that trying to shoehorn validation into Model.save() is an anti-pattern. It runs counter to Django's design, and will probably cause problems down the road.

You've already found the "perfect solution", which is to use Model.full_clean() to do the validation. I don't agree with you that remembering this will be burdensome for developers. I mean, remembering to do anything right can be hard, especially with a large and powerful framework, but this particular thing is straightforward, well documented, and fundamental to Django's ORM design.

This is especially true when you consider what is actually, provably difficult for developers, which is the error handling itself. It's not like developers could just do model.validate_and_save(). Rather, they would have to do:

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

Whereas Django's idiom is:

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

I don't find Django's version any more difficult. (That said, there's nothing stopping you from writing your own validate_and_save convenience method.)

Finally, I would suggest adding a database constraint for your requirement as well. This is what Django does when you add a constraint that it knows how to enforce at the database level. For example, when you use unique=True on a field, Django will both create a database constraint and add Python code to validate that requirement. But if you want to create a constraint that Django doesn't know about you can do the same thing yourself. You would simply write a Migration that creates the appropriate database constraint in addition to writing your own Python version in clean(). That way, if there's a bug in your code and the validation isn't done, you end up with an uncaught exception (IntegrityError) rather than corrupted data.

这篇关于无论数据源如何,使用Django / Django Rest Framework验证和保存数据的正确过程是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆