Django Rest Framework没有序列化SerializerMethodField

时间:2016-04-01 20:28:17

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

我有2个型号:

from django.db import models

STATUSES = (
    ('f', 'Finished'),
)


class Battery(models.Model):
    energy = models.CharField(max_length=10)
    current = models.CharField(max_length=10)


class Charger(models.Model):
    status = models.CharField(max_length=1, choices=STATUSES)

我想创建序列化器,将这两个模型序列化在一起。我的serializers.py:

from rest_framework import serializers
from .models import Battery, Charger


class BatterySerializer(serializers.ModelSerializer):
    class Meta:
        model = Battery


class ChargerSerializer(serializers.ModelSerializer):
    status = serializers.SerializerMethodField()

    class Meta:
        model = Charger

    def get_status(self, obj):
        return obj.get_status_display()


class DeviceSerializer(serializers.Serializer):
    battery = BatterySerializer()
    charger = ChargerSerializer()
    some_field = serializers.CharField()

由于Charger模型在状态字段中有选择,我添加SerializerMethodField以显示完整状态。然后我创建一个这样的视图:

class DeviceView(APIView):
    def get(self, request, format=None):
        battery = Battery.objects.get(id=1)
        charger = Charger.objects.get(id=1)
        battery_serializer = BatterySerializer(battery)
        charger_serializer = ChargerSerializer(charger)
        serializer = DeviceSerializer(data={
            'battery': battery_serializer.data,
            'charger': charger_serializer.data,
            'some_field': 'some_text'
        })
        if serializer.is_valid():
            return Response(serializer.validated_data)
        else:
            return Response(status = 500)

但是当我调用此视图时,它返回带有空充电器字段的json:

{
    "battery": {
        "energy": "12",
        "current": "34"
    },
    "charger": {},
    "some_field": "some_text"
}

但是当我创建一个仅序列化Charger模型的视图时:

class ChargerView(APIView):
    def get(self, request, format=None):
        charger = Charger.objects.get(id=1)
        charger_serializer = ChargerSerializer(charger)
        return Response(charger_serializer.data)

它有效并返回此json:

{
    "id": 1,
    "status": "Finished"
}

为什么会这样?我在哪里弄错了?

3 个答案:

答案 0 :(得分:6)

查看Serializers的文档:

    当你有一个对象并且你必须序列化它时,会传递
  1. instance(link)
  2. 当您已经有序列化数据并且想要反序列化它并从中创建实例时,会传递
  3. data(link)
  4. 如果您有实例并且想要更新它,则会传递instancedata(link)
  5. 考虑一下你的情况,我认为你不需要选项2和3,因为你有batterycharger个实例,你需要将它们序列化。您没有创建新实例,也不必验证它,因此不需要将其作为data传递。

    有两种方法可以做到这一点:

    1.创建一个类Device,以便您可以创建它的实例,然后使用DeviceSerializer对其进行序列化:

    class Device(object):
    
        def __init__(self, battery, charger, some_field):
            self.battery = battery
            self.charger = charger
            self.some_field  = some_field
    
    class DeviceView(APIView):
        # then in the DeviceView you could create an instance and pass to the serializer
        def get(self, request, format=None):
            battery = Battery.objects.get(id=1)
            charger = Charger.objects.get(id=1)
            device = Device(battery=battery, charger=charger, some_field='some_text')
            serializer = DeviceSerializer(instance=device)
            return Response(serializer.data)
    

    2.如果您不想创建新课程,可以直接创建dict并将其作为实例传递:

    class DeviceView(APIView):
        def get(self, request, format=None):
            battery = Battery.objects.get(id=1)
            charger = Charger.objects.get(id=1)
            # create a dict with required objects and pass it as instance of serializer
            device = {'battery': battery, 'charger': charger, 'some_field': 'some_text'}
            serializer = DeviceSerializer(instance=device)
            return Response(serializer.data)    
    

答案 1 :(得分:1)

好像你正在做你不必做的工作。如果您在将充电器传递到DeviceSerializer之前对其进行序列化,那么您实际上正在传递dict,而不是Charger个实例,dict没有{{} 1}}方法。您应该直接传递get_status_displayBattery

Charger

请注意,您还可以使用CharField:

替换SerializerMethodField来简化
class DeviceView(APIView):
    def get(self, request, format=None):
        battery = Battery.objects.get(id=1)
        charger = Charger.objects.get(id=1)
        serializer = DeviceSerializer(instance={
            'battery': battery,
            'charger': charger,
            'some_field': 'some_text',
        })
        return Response(serializer.data)

编辑:正如AKS指出的那样,序列化时应该传递class ChargerSerializer(serializers.ModelSerializer): status = serializers.CharField(source='get_status_display') class Meta: model = Charger 而不是instance序列化(data用于反序列化),并且您不需要检查data

答案 2 :(得分:1)

在创建序列化程序实例时传递关键字数据,仅在反序列化数据时使用。 您应该使用包含所需字段的对象创建DeviceSerializer。 我没有测试过,但可能是这样的

class Device(object):
    def __init__(self, battery, charger, name, ):
        self.battery = battery
        self.charger = charger
        self.some_field = name

class DeviceView(APIView):
    def get(self, request, format=None):

        d=Device(Battery.objects.get(id=1),Charger.objects.get(id=1),"somename")
        serializer = DeviceSerializer(d)
            return Response(serializer.data)