如何序列化不是来自请求的数据并正确验证它(Django Rest框架中的ModelSerializer)?

如何序列化不是来自请求的数据并正确验证它(Django Rest框架中的ModelSerializer)?,django,validation,serialization,django-rest-framework,Django,Validation,Serialization,Django Rest Framework,使用Django Rest Framework 3、基于函数的视图和ModelSerializer(更具体地说是HyperlinkedModelSerializer) 当用户从客户端提交表单时,我有一个视图,它获取请求数据,使用它调用外部API,然后使用外部API中的数据填充模型序列化程序的数据。 我相信这部分工作正常,从我读到的内容来看,您应该使用上下文和验证() 在我的模型序列化程序中,到目前为止,我只有一个overidden函数: from django.core.validators i

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

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

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

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\u url
bar\u url
字段),我感到困惑的是验证是如何不起作用的。如果我给它错误的数据,模型序列化程序不会拒绝它

我假设在
validate()
中,通过将上下文数据添加到数据中,当调用
is\u validate()
时,将检查数据的有效性。可能不是这样,特别是当我打印出
s
(在使用序列化程序之后,但在调用
is\u valid()
之前)时,没有迹象表明请求对象的
数据已由
validate()
中的上下文数据填充(我不知道是否应该填充)

因此,我尝试在
validate()
方法中直接调用URLvalidator,但似乎仍然不起作用。尽管提供了无效数据,如“asdf”或空python dict({}),但没有错误。我的测试断言表明,该字段确实包含像“{}”这样的无效数据


正确的方法是什么?

您没有调用验证器

通过执行
URLValidator(data['bar\u 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不会自动调用
.full\u clean
方法,这样您就可以用无效值保存模型实例(除非约束在数据库级别)。

我也不明白这是如何通过Django的模型验证的,因为'asdf'或'{}'不是有效的URLField数据。非常感谢,似乎我误读了文档。我认为在调用is_valid()之前,request.data是不可访问的(有点像Django表单数据)。我假设Django在验证之前出于某种原因使其表单数据不可变。像这样编辑请求数据一般可以吗?好的,我们解释了请求不可变的原因。我个人认为这样向请求添加数据是可以的,这样序列化过程就可以保持不变。