django rest framework SerializerMethodField 奇怪的行为

Posted

技术标签:

【中文标题】django rest framework SerializerMethodField 奇怪的行为【英文标题】:django rest framework SerializerMethodField bizarre behaviour 【发布时间】:2016-05-23 18:56:29 【问题描述】:

当两个序列化器类声明一个同名的 SerializerMethodField 时,像这样:

class APIProfileSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):

        super(APIProfileSerializer, self).__init__(*args, **kwargs)
        self.request = request

    def get_image(self, instance):

        if instance.image:
            return self.request.build_absolute_uri(location=instance.image.url)
        return None

    image = serializers.SerializerMethodField()

    # other ProfileSerializer fields

    class Meta:
        model = User
        fields = ('image')



class ProfileSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):

        super(ProfileSerializer, self).__init__(*args, **kwargs)
        self.request = request

    def get_image(self, instance):

        if instance.image:
            return self.request.build_absolute_uri(location=instance.image.url)
        return None

    image = serializers.SerializerMethodField()

    # other ProfileSerializer fields

    class Meta:
        model = User
        fields = ('image')

代码

serializer = APIProfileSerializer(instance=request.user, request=request)
return Response(data=serializer.data)

崩溃并带有以下回溯:

Traceback(最近一次调用最后一次): 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/django/core/handlers/base.py”,第 174 行,在 get_response response = self.process_exception_by_middleware(e, request) 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/django/core/handlers/base.py”,第 172 行,在 get_response 响应 = response.render() 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/django/template/response.py”,第 160 行,在渲染中 self.content = self.rendered_content 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/rest_framework/response.py”,第 71 行,在 render_content 中 ret = renderer.render(self.data, media_type, context) 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/rest_framework/renderers.py”,第 675 行,在渲染中 上下文 = self.get_context(数据,accepted_media_type,renderer_context) 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/rest_framework/renderers.py”,第 618 行,在 get_context raw_data_put_form = self.get_raw_data_form(数据,视图,'PUT',请求) 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/rest_framework/renderers.py”,第 540 行,在 get_raw_data_form content = renderer.render(serializer.data, 接受, 上下文) 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/rest_framework/serializers.py”,第 503 行,数据 ret = super(Serializer, self).data 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/rest_framework/serializers.py”,第 239 行,数据 self._data = self.to_representation(self.instance) to_representation 中的文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/rest_framework/serializers.py”,第 472 行 ret[field.field_name] = field.to_representation(属性) 文件“/home/ubuntu/venv/superhq_rest/lib/python3.4/site-packages/rest_framework/fields.py”,第 1645 行,在 to_representation 返回方法(值) 文件“/home/ubuntu/vhosts/superhq_backend/account/serializers.py”,第 32 行,在 get_image 返回 self.request.build_absolute_uri(location=instance.image.url) AttributeError: 'NoneType' 对象没有属性 'build_absolute_uri'

(我的第一个问题是:如何让traceback在markdown中更具可读性?=))

就像request 没有被传递给序列化器

但是,这个

serializer = ProfileSerializer(instance=request.user, request=request)
return Response(data=serializer.data)

还有这个

serializer = APIProfileSerializer(instance=request.user,request=request)
_data = serializer.data,
return Response(data=_data)

工作正常...

调试显示APIProfileSerializer和ProfileSerializer都被调用,崩溃是因为在ProfileSerializer中调用get_image而没有传递request给它

所以,问题是:WTF?!我没有调用这个序列化程序!我什至从未在我的观点中提及它!它是如何以及出于什么原因被调用的?

我坚持使用后一个代码片段来解决这个问题,但一定有更好的方法!有什么建议吗?

【问题讨论】:

【参考方案1】:

我是这样解决的:

改变了

if instance.image:

if instance.image and self.request:

因此,这些没有正确 self.request 的底层 get_image() 调用不会再导致崩溃。

不过,很高兴知道为什么会发生上述所有情况

【讨论】:

【参考方案2】:

如果request 已提供给序列化程序上下文,DRF 的 ImageField 似乎会返回完整的 URL,因此不需要显式的 URL 构造。干净优雅(需要研究源代码 - 官方文档没有提到这一点)

【讨论】:

以上是关于django rest framework SerializerMethodField 奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

在 Django REST Framework 的 CreateAPIView 中的 create() 之后返回不同的序列化程序

17-Django-Django REST framework-REST framework及RESTful简介

怎么安装django rest framework

Django-rest-framework 和 django-rest-framework-jwt APIViews and validation Authorization headers

Django Rest Framework 和 django Rest Framework simplejwt 两因素身份验证

django rest framework中文介绍