REST框架:POST一个FK,返回内联模型

时间:2014-09-29 16:12:49

标签: django django-rest-framework

我有一个rest_framework.ViewSet使用内联序列化器(BarSerializer)来显示我的Bar模型以及我的Foo模型。

class FooSerializer(serializers.ModelSerializer):

        bar = BarSerializer()

        class Meta:
            model = Foo
            fields = ("name", "bar")

/api/foos/1/的调用会返回:

{
    "bar": {"name": "bar", "number": 1}, 
    "name": "up"
}

但是,我想创建一个带有由foreignkey引用的Bars的新Foos。

POST到/api/foos/会创建一个新的Foo。

{
    "bar": 1, 
    "name": "up"
}

使用标准ViewSet似乎是不可能的。在理想的世界中,我使用ForeignKey进行POST并获得“内联”模型。

目前我正在覆盖get_serializer_class和create methods以返回每个请求的不同序列化程序。由于这似乎是一个相当常见的用例,我有什么遗漏吗?

1 个答案:

答案 0 :(得分:1)

使用以下代码段,您可以将PK值序列化为所需数据,而保存时您只能提供PK值

from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.utils.encoding import smart_text
from rest_framework import serializers

class CustomRelatedField(serializers.RelatedField):
    """
    Represents a primary key relationship with {'pk':1,'name': 'foo'}
    """
    read_only = False

    default_error_messages = {
        'does_not_exist': ("Invalid pk '%s' - object does not exist."),
        'incorrect_type': ('Incorrect type.  Expected {"id": 1} format , received %s.'),
    }

    def __init__(self, *args, **kwargs):
        self.fields = kwargs.pop('fields', ('id',))
        return super(CustomRelatedField, self).__init__(*args, **kwargs)


    def to_native(self, obj):
        data = {'id':obj.pk}
        for field in self.fields:
            value = getattr(obj, field)
            data[field] = value
        return data

    def from_native(self, data):
        if isinstance(data, int):
            data = {'id':data}
        if not isinstance(data, dict):
            received = type(data).__name__
            msg = self.error_messages['incorrect_type'] % received
            raise ValidationError(msg)
        if self.queryset is None:
            raise Exception('Writable related fields must include a `queryset` argument')

        try:
            return self.queryset.get(pk=data.get('id'))
        except ObjectDoesNotExist:
            msg = self.error_messages['does_not_exist'] % smart_text(data)
            raise ValidationError(msg)
        except (TypeError, ValueError):
            received = type(data).__name__
            msg = self.error_messages['incorrect_type'] % received
            raise ValidationError(msg)

class FooSerializer(serializers.ModelSerializer):
    bar = CustomRelatedField(fields=('id','name', 'number'))

    class Meta:
        model = Foo
        fields = ("name", "bar")