如何序列化不是来自请求的数据并正确验证它(Django Rest Framework 中的 ModelSerialize



使用 Django Rest Framework 3、基于函数的视图和 ModelSerializer(更具体地说是 HyperlinkedModelSerializer)。

当用户从客户端提交表单时,我有一个视图,该视图获取请求数据,使用它调用外部 API,然后使用来自外部 API 的数据填充模型序列化程序的数据。我相信我这部分工作正常,从我读到的内容来看,你应该使用上下文validate()

在我的模型序列化程序中,到目前为止,我只有一个覆盖函数:

from django.core.validators import URLValidator
def validate(self, data):
if 'foo_url' in self.context:
data['foo_url'] = self.context['foo_url']
URLValidator(data['foo_url'])
if 'bar_url' in self.context:
data['bar_url'] = self.context['bar_url']
URLValidator(data['bar_url'])
return super(SomeSerializer, self).validate(data)

以防万一,相关的视图代码如下所示:

context = {'request': request}
...
context['foo_url'] = foo_url
context['bar_url'] = bar_url
s = SomeSerializer(data=request.data, context=context)
if s.is_valid():
s.save(user=request.user)
return Response(s.data, status=status.HTTP_201_CREATED)

现在假设我的想法是正确的(我的模型确实从相应的上下文数据中填充了它的foo_urlbar_url字段),我感到困惑的是验证是如何不起作用的。 如果我给它错误的数据,模型序列化程序不会拒绝它。

我假设在validate()中,通过将上下文数据添加到数据中,当调用is_valid()时,将检查数据的有效性。 也许情况并非如此,尤其是当我打印出s时(在使用序列化程序之后但在调用is_valid()之前),没有迹象表明请求对象的data已填充了来自validate()的上下文数据(我不知道是否应该如此)。

所以我尝试直接在validate()方法中调用 URLValidators,但似乎仍然不起作用。 尽管给了它无效的数据,如"asdf"或空的python字典({}),但没有错误。 我的测试断言表明该字段确实包含无效数据,例如"{}"。

正确的方法是什么?

你没有调用验证器。

通过这样做URLValidator(data['bar_url'])您实际上是在构建一个具有自定义方案的 url 验证器(请参阅文档),仅此而已。正确的代码应该是:

URLValidator()(data['bar_url'])

在其中构建默认 url 验证程序,然后验证值。


但无论如何我不会使用这种方法,而是直接添加额外的数据(不使用上下文),并让 DRF 通过声明正确的字段进行验证:

# Somewhere in your view
request.data['bar_url'] = 'some_url'
# In serializer:
class MySerializer(serializers.ModelSerializer):
bar_url = serializers.URLField()
class Meta:
fields = ('bar_url', ...)

回答您的评论

我也不明白这也是如何通过 Django 的模型验证

看到这个答案: 为什么 django 的 model.save() 不调用 full_clean()?

默认情况下,Django 不会自动调用.full_clean方法,因此您可以保存具有无效值的模型实例(除非约束在数据库级别)。

最新更新