[英]Django Rest Framework doesn't serialize SerializerMethodField
I have 2 models: 我有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)
And I want to create serializer that will serialize this 2 models together. 我想创建将这两个模型序列化在一起的序列化器。 My serializers.py:
我的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()
Because Charger model has choices in status field I add SerializerMethodField for displaying full status. 因为Charger模型在状态字段中有选择,所以我添加了SerializerMethodField以显示完整状态。 Then I create a view like this:
然后,我创建一个像这样的视图:
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)
But when I call this view it returns json with empty charger field: 但是当我调用此视图时,它返回带有空充电器字段的json:
{
"battery": {
"energy": "12",
"current": "34"
},
"charger": {},
"some_field": "some_text"
}
But when I create a view that serialize only Charger model: 但是,当我创建仅序列化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)
It works and it returns this json: 它有效,并返回此json:
{
"id": 1,
"status": "Finished"
}
Why this happens? 为什么会这样? Where did I make a mistake?
我在哪里弄错了?
Looking at the documentation of Serializers
: 查看
Serializers
的文档:
instance
is passed when you have an object and you have to serialize it. instance
在您有对象且必须对其进行序列化时传递。 (link) data
is passed when you already have serialized data and you want to deserialize it and create an instance out of it. data
时,你已经序列化的数据传递,你想反序列化和出它创建一个实例。 (link) instance
and data
is passed when you have an instance and you want to update it. instance
和data
被传递。 (link) Looking at your case, I don't think you need option 2 and 3 because you have the battery
and charger
instances and you need to serialize it together. 考虑到您的情况,我认为您不需要选项2和3,因为您有
battery
和charger
实例,需要一起序列化。 You are not creating a new instance and you also don't have to validate it so passing it as data
is not required. 您无需创建新实例,也不必验证它,因此不需要将其作为
data
传递。
There are two ways you could do this: 有两种方法可以执行此操作:
1.Create a class Device
so you could create an instance of it and then serialize it using DeviceSerializer
: 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.If you don't want to go with creating a new class you could directly create a dict
and pass it as instance: 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)
Seems like you're doing work you don't have to. 好像您在做不必要的工作。 If you serialize the charger before passing it to the
DeviceSerializer
, you're actually passing a dict
, not a Charger
instance, and the dict
has no get_status_display
method. 如果在将充电器传递给
DeviceSerializer
之前对其进行序列化,则实际上是传递的是dict
,而不是Charger
实例,并且该dict
没有get_status_display
方法。 You should pass the Battery
and Charger
directly like so: 您应该像这样直接通过
Battery
和Charger
:
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)
Note that you can also simplify by replacing the SerializerMethodField with a CharField: 请注意,您还可以通过用CharField替换SerializerMethodField来简化操作:
class ChargerSerializer(serializers.ModelSerializer):
status = serializers.CharField(source='get_status_display')
class Meta:
model = Charger
Edit: As AKS pointed out, a serializer should be passed instance
rather than data
when serializing ( data
is for deserializing), and you don't need to check .is_valid()
编辑:正如AKS所指出的,序列化时应将序列化器而不是
data
传递给instance
( data
用于反序列化),并且您不需要检查.is_valid()
you are passing the keyword data when creating the serializer instance, witch is only used when deserializing data. 您在创建序列化程序实例时传递关键字数据,仅当反序列化数据时才使用witch。 you should create the DeviceSerializer with an object with the fields you want.
您应该使用带有所需字段的对象创建DeviceSerializer。 I haven't tested, but maybe something like this
我还没有测试过,但也许像这样
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.