Reputation: 3573
I'm trying to add routes to GET and PUT the status of a ticket.
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']
By default this serializer expects the JSON to be of the form { 'status': '...' }
, but I want to remove the status key and use the value directly. My to_internal_value
works fine, but when I remove the nested status in to_representation
I end up with an error at
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
This is the relevant section of my 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)
Upvotes: 0
Views: 94
Reputation: 752
DRF Serializers are designed for django ORM which means that it manipulates django models and primitive dictionaries.
I prefer you to bypass this behaviour directly in status action. You can leave to_representation
method in you serializer with native behaviour and edit status action to return only status string (use serializer.instance
parameter to get serializer.instance.status
string and return it in Response object....
So in short: leave native to_representation
method and 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)
Upvotes: 1