我对django和python很新,我试图学习rest_framework来创建RESTful API。
所以我有一个这样的模型:
class Listing(models.Model):
listingid = models.BigIntegerField(primary_key=True)
sellerid = models.IntegerField()
createdon = models.DateTimeField(auto_now_add=True, editable=False)
expirydate = models.DateTimeField(null=True)
validationstatus = models.SmallIntegerField(default=0)
listingstatus = models.SmallIntegerField(
choices=((0, 'Active'),
(1, 'Hidden'),
(2, 'Suspended'),
(4, 'Expired'),
(5, 'Deleted'),
),
default=0)
现在我需要验证 expirydate 总是大于 createdon 日期。
我知道我可以在视图中执行此操作,我想这不是一个好主意,因为现在验证仅存在于视图中。
所以这给我留下了序列化器和模型。
我知道我可以覆盖save
方法进行检查,如下所示:
class MasterListing(models.Model):
# fields here..
def save(self, *args, **kwargs):
if self.expirydate > self.createdon:
super().save(*args, **kwargs)
return ValidationError("Expiry date cannot be greater than created date ("++")")
但我不知道这是不是一个好主意,因为现在我提出了程序员可能忘记捕获的错误。我也不确定当这个方法运行时是否会填充字段
我在文档中看到的另一种方式是clean
方法,我无法理解它。
当你使用rest_framework时,有人可以指导我如何处理这样的情况吗? 到目前为止我已经阅读过有关验证的一些内容:
clean
方法save
方法似乎有这么多的选择,我甚至可能留下了一些,我无法清楚地知道何时使用。 我很抱歉,如果这是初学者级别的一点,但我是框架的新手,django似乎与我在PHP中做的非常不同。欢迎任何建议!
编辑:我将仅使用django进行rest_framework,而不是其他任何东西,因为我们只想构建RESTful API。
答案 0 :(得分:4)
用于调用Model.clean
的Django REST框架,以前是推荐需要在Django表单和DRF序列化程序中使用的验证逻辑的地方。 自DRF 3.0起,this is no longer the case 和Model.clean
将不再被称为during the validation cycle。通过这种更改,现在有两个可能放置在多个字段上的自定义验证逻辑的位置。
如果您只使用Django REST框架进行验证,并且您没有任何其他需要手动验证数据的区域(如ModelForm
或Django)管理员),然后你应该看看Django REST framework's validation framework。
class MySerializer(serializers.ModelSerializer):
# ...
def validate(self, data):
# The keys can be missing in partial updates
if "expirydate" in data and "createdon" in data:
if data["expirydate"] < data["createdon"]:
raise serializers.ValidationError({
"expirydata": "Expiry date cannot be greater than created date",
})
return super(MySerializer, self).validate(data)
如果你需要将Django REST框架与使用模型级验证的Django组件结合使用(比如Django管理员),你有两个选择。
Model.clean
和Serializer.validate
中复制您的逻辑,违反DRY principle并为未来问题做好准备。Model.save
进行验证,并希望以后不会发生任何奇怪的事。但我不知道这是不是一个好主意,因为现在我提出了程序员可能忘记捕获的错误。
我冒昧地说,提出错误会比保存的数据更有可能变得无效。一旦开始允许无效数据,您必须在使用数据的任何地方进行检查来修复它。如果您不允许它进入无效状态,则不会遇到该问题。
我也不确定在运行此方法时是否会填充字段。
您应该可以假设,如果要保存某个对象,那么这些字段已经填充了它们的值。
答案 1 :(得分:2)
如果你想使用Django REST Framework 3.0进行模型验证和串行器验证,你可以强制你的序列化器使用这样的模型验证(所以你不要自己重复):
import rest_framework, django
from rest_framework import serializers
class MySerializer(serializers.ModelSerializer):
def validate(self, data):
for key, val in data.iteritems():
setattr(self.instance, key, val)
try:
self.instance.clean()
except django.core.exceptions.ValidationError as e:
raise rest_framework.exceptions.ValidationError(e.message_dict)
return data
我考虑过从我的模型的clean()函数的代码生成一个新函数,并根据参数django.core.exceptions.ValidationError
(或其他东西)吐出rest_framework.exceptions.ValidationError
或source
到功能。然后我会从模型和序列化器中调用它。但这对我来说似乎不太好。
答案 2 :(得分:0)
如果要确保数据在最低级别上有效,请使用模型验证(它应该由序列化程序类以及(模型)表单类(例如,admin)运行。)
如果您希望仅在API /表单中进行验证,请将其放在序列化程序/表单类中。因此,验证的最佳位置应为Model.clean()
。
验证应该永远不会在视图中发生,因为它们不应该过于膨胀,真正的业务逻辑应该封装在模型或表单中。