Удаление вложенности из ModelSerializer
Я пытаюсь добавить маршруты для GET и PUT статуса билета.
class ReturnLabelTicket(models.Model):
status = models.CharField(choices=...)
class ReturnLabelTicketStatusSerializer(serializers.ModelSerializer):
"""Serializer of a return label ticket status."""
status = serializers.ChoiceField(ReturnLabelTicket.StatusChoice.choices)
def to_internal_value(self, data):
"""Take the whole data value as the status."""
return super().to_internal_value({'status': data})
def to_representation(self, instance):
"""Return the status string."""
return instance.status
def update(self, instance, validated_data):
"""Update the ticket status."""
instance.status = validated_data.get('status', instance.status)
instance.save()
return instance
class Meta:
model = ReturnLabelTicket
fields = ['status']
По умолчанию этот сериализатор ожидает, что JSON будет иметь форму { 'status': '...' }
, но я хочу удалить ключ статуса и использовать значение напрямую. Мой to_internal_value
работает нормально, но когда я удаляю вложенный статус в to_representation
, я получаю ошибку в
ticketing-service | File "/opt/app-root/lib64/python3.9/site-packages/rest_framework/serializers.py", line 549, in data
ticketing-service | return ReturnDict(ret, serializer=self)
ticketing-service | File "/opt/app-root/lib64/python3.9/site-packages/rest_framework/utils/serializer_helpers.py", line 18, in __init__
ticketing-service | super().__init__(*args, **kwargs)
ticketing-service | ValueError: need more than 1 value to unpack
Вот соответствующий раздел моего ReturnLabelTicketViewSet
.
@action(
detail=True,
url_path='status',
serializer_class=ReturnLabelTicketStatusSerializer
)
def status(self, _request, ticket_id=None):
"""Retrieve the ticket status."""
ticket = self.get_object()
serializer = self.get_serializer(ticket)
return Response(serializer.data)
DRF Serializers разработаны для django ORM, что означает, что они манипулируют моделями django и примитивными словарями.
Я предпочитаю обойти это поведение непосредственно в действии статуса. Вы можете оставить метод to_representation
в вашем сериализаторе с нативным поведением и отредактировать действие status, чтобы оно возвращало только строку статуса (используйте параметр serializer.instance
для получения строки serializer.instance.status
и возвращайте ее в объект Response....
Короче говоря: оставьте родной метод to_representation
и return Response(serializer.instance.status)
class ReturnLabelTicketStatusSerializer(serializers.ModelSerializer):
"""Serializer of a return label ticket status."""
status = serializers.ChoiceField(ReturnLabelTicket.StatusChoice.choices)
def to_internal_value(self, data):
"""Take the whole data value as the status."""
return super().to_internal_value({'status': data})
def update(self, instance, validated_data):
"""Update the ticket status."""
instance.status = validated_data.get('status', instance.status)
instance.save()
return instance
class Meta:
model = ReturnLabelTicket
fields = ['status']
@action(
detail=True,
url_path='status',
serializer_class=ReturnLabelTicketStatusSerializer
)
def status(self, _request, ticket_id=None):
"""Retrieve the ticket status."""
ticket = self.get_object()
serializer = self.get_serializer(ticket)
return Response(serializer.instance.status)