Django Rest Framework在POST中接收主键值并将模型对象作为嵌套序列化器返回

时间:2016-03-23 21:46:50

标签: python json django serialization django-rest-framework

我不能完全确定我的问题标题是否符合我的要求,但情况确实如此:

我的HyperlinkedModelSerializer看起来像这样:

class ParentArrivalSerializer(serializers.HyperlinkedModelSerializer):
    carpool = SchoolBuildingCarpoolSerializer()

    class Meta:
        model = ParentArrival

正如您所看到的,carpool被定义为嵌套的序列化器对象,我想要的是能够以这种方式发出POST请求来创建ParentArrival(数据为application / json ):

{
    ...
    "carpool": "http://localhost:8000/api/school-building-carpools/10/"
    ...
}

以这种方式接收数据:

{
    "carpool": {
        "url": "http://localhost:8000/api/school-building-carpools/10/"
        "name": "Name of the carpool",
        ...
    }
}

基本上,我正在寻找一种处理嵌套序列化程序的方法,而不必在POST请求中将数据作为对象(但在这种情况下为id或url)发送,但接收对象嵌套在序列化响应中

4 个答案:

答案 0 :(得分:8)

我对之前的解决方案感到满意,但我决定重新审视,我认为我还有另一种解决方案可以完全满足您的需求。

基本上,您需要创建自己的自定义字段,并且只需覆盖to_representation方法:

class CarpoolField(serializers.PrimaryKeyRelatedField):
    def to_representation(self, value):
        pk = super(CarpoolField, self).to_representation(value)
        try:
           item = ParentArrival.objects.get(pk=pk)
           serializer = CarpoolSerializer(item)
           return serializer.data
        except ParentArrival.DoesNotExist:
           return None

    def get_choices(self, cutoff=None):
        queryset = self.get_queryset()
        if queryset is None:
            return {}

        return OrderedDict([(item.id, str(item)) for item in queryset])

class ParentArrivalSerializer(serializers.HyperlinkedModelSerializer):
    carpool = CarpoolField(queryset=Carpool.objects.all())

    class Meta:
        model = ParentArrival

这将允许您使用

发布
{
     "carpool": 10
}

并获得:

{
    "carpool": {
        "url": "http://localhost:8000/api/school-building-carpools/10/"
        "name": "Name of the carpool",
        ...
    }
}

答案 1 :(得分:4)

很简单。 如您所知,Django appends "_id" to the field name在ModelClass中,您可以在SerializerClass中实现,也可以实现原始文件。您要做的就是这样

class ParentArrivalSerializer(serializers.HyperlinkedModelSerializer):
    # ...
    carpool_id = serializers.IntegerField(write_only=True)
    carpool = SchoolBuildingCarpoolSerializer(read_only=True)
    # ...
    class Meta:
        fields = ('carpool_id', 'carpool', ...)

并在POST请求中使用carpool_id

答案 2 :(得分:2)

一种方法是将“拼车”保留为您从DRF获取的默认值,然后为嵌套对象添加只读字段。

这样的事情(我没有时间测试代码,所以请考虑这个伪代码。如果你不能让它工作,请告诉我,并将花更多的时间):

class ParentArrivalSerializer(serializers.HyperlinkedModelSerializer):
    carpool_info = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = ParentArrival
        fields = ('id', 'carpool', 'carpool_info',)

    def get_carpool_info(self, obj):
         carpool = obj.carpool
         serializer = SchoolBuildingCarpoolSerializer(carpool)
         return serializer.data

如果您的唯一嵌套对象是拼车,我还建议切换到常规ModelSerializer,因此拼车只显示ID(10),然后嵌套对象可以显示URL。

 class ParentArrivalSerializer(serializers.ModelSerializer):
     ....

然后如果一切正常,你就可以用

做一个帖子
{
     "carpool": 10
}

和你的获得:

{
    "carpool": 10
    "carpool_info": {
        "url": "http://localhost:8000/api/school-building-carpools/10/"
        "name": "Name of the carpool",
        ...
    }
}

我从未找到另一种解决方案,所以这是我多次使用的技巧。

答案 3 :(得分:2)

覆盖to_representation方法怎么样?

class YourSerializer(serializers.ModelSerializer):

    class Meta:
        model = ModelClass
        fields = ["id", "foreignkey"]

    def to_representation(self, instance):
        data = super(YourSerializer, self).to_representation(instance)
        data['foreignkey'] = YourNestedSerializer(instance.foreignkey).data
        return data