2016-04-01 3 views
3

У меня есть 2 модели:Джанго Rest Framework не сериализовать SerializerMethodField

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) 

И я хочу, чтобы создать сериалайзер, которые будут сериализуете 2 модели вместе. Мой 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() 

Поскольку зарядное устройство модель имеет выбор в поле статуса добавить 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" 
} 

Но когда я создать представление, что сериализации только зарядное устройство модель:

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" 
} 

Почему это происходит? Где я совершил ошибку?

+0

почему вы не можете назвать как' Аккумуляторы erializer' и 'ChargerSerializer' независимо от вашего зрения и вернуть их? Так как это делает ваш 'DeviceSerializer'. – dnit13

+0

Как я могу вернуть их вместе? –

+0

вот этот '{ 'батарея': батарея .__ dict__, 'charger': charger .__ dict__, 'some_field': 'some_text' }'? не уверен, что это правильный путь. – dnit13

ответ

5

Глядя на документацию Serializers:

  1. instance передается, когда у вас есть объект, и вы должны сериализовать его. (link)
  2. data передается, когда у вас уже есть сериализованные данные, и вы хотите десериализовать его и создать экземпляр из него. (link)
  3. как instance, так и data передается, когда у вас есть экземпляр, и вы хотите его обновить.(link)

Глядя на вашем случае, я не думаю, что вам нужен вариант 2 и 3, потому что у вас есть battery и charger экземпляров, и вам необходимо сериализовать его вместе. Вы не создаете новый экземпляр, и вам также не нужно его проверять, так как передача его data не требуется.

Есть два способа вы могли бы сделать это:

1.Create класс 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

Похоже, вы делаете работу, которой вам не нужно. Если вы сериализуете зарядное устройство перед его передачей на DeviceSerializer, вы фактически передаете dict, а не Charger, а dict не имеет метода get_status_display. Вы должны пройти 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) 

Обратите внимание, что вы можете также упростить, заменив SerializerMethodField с CharField:

class ChargerSerializer(serializers.ModelSerializer): 
    status = serializers.CharField(source='get_status_display') 

    class Meta: 
     model = Charger 

Edit: Как АКС отметил, сериализатор должна быть прошло instance, а не data при сериализации (data для десериализации), и вам не нужно, чтобы проверить .is_valid()

+0

Это не работает. 'Недопустимые данные, ожидаемый словарь, но получил Батарею/Зарядное устройство –

+0

Отредактировано для передачи dict как' instance' вместо 'data' – Fush

1

вы па петь данные ключевых слов при создании экземпляра serializer, ведьма используется только при десериализации данных. вы должны создать 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) 
Смежные вопросы