Reputation: 11523
I'm wondering which is the best way to solve this, I have a nested serializer like this:
serializers.py:
class PaymentMethodSerializer(serializers.ModelSerializer):
data = serializers.JSONField()
payment_type = PaymentTypeSerializer(required=False)
Then, the view looks something like this:
class PaymentMethodView(APIView):
def put(self, request, id):
try:
payment_method = PaymentMethod.objects.get(id=id)
except ObjectDoesNotExist:
return Response("No PaymentMethod with that id", status=status.HTTP_404_NOT_FOUND)
payment_method_serialized = PaymentMethodSerializer(instance=payment_method, data=request.data)
payment_type = request.data.get("payment_type", None)
if payment_type:
try:
payment_method_type = PaymentType.objects.get(id=payment_type)
except ObjectDoesNotExist:
payment_method_type = None
else:
payment_method_type = None
# Now, call is_valid()
if payment_method_serialized.is_valid():
payment_method_serialized.save(payment_type=payment_method_type)
return Response(payment_method_serialized.data, status=status.HTTP_200_OK)
is_valid()
returns False and this error:
{"payment_type":{"non_field_errors":["Invalid data. Expected a dictionary, but got int."]}}
I understand it, I'm giving the serializer a pk
. However I don't want to create a new serializer with a PrimaryKeyRelatedField
instead of the nested relationship just for this. How can I get the PaymentType
that corresponds to that pk
and then add that object to the request.data
dictionary so that is_valid
doesn't fail? is it the best way to solve this?
Upvotes: 1
Views: 2384
Reputation: 8897
Suppose payment_type
is ForeignKey
field in a PaymentMethod
model, with null=True
because of required=False
.
If you provide only a pk
so you don't need serializer for it field, you can just write in fields
, like all other fields.
class PaymentMethodSerializer(serializers.ModelSerializer):
data = serializers.JSONField()
class Meta:
model = PaymentMethod
fields = ('data', 'payment_type')
It will accept pk
or None
. If you want to provide special representation for your PaymentType
model, you can override a to_representation()
method.
class PaymentMethodSerializer(serializers.ModelSerializer):
...
def to_representation(self, instance):
representation = super(PaymentMethodSerializer, self).to_representation(instance)
representation['payment_type'] = PaymentTypeSerializer(instance.payment_type).data
return representation
Now it will use PaymentTypeSerializer for representation of related PaymentType
model.
You can move you payment_type
validation in a serializer
though. Override to_internal_value
, check provided PaymentType
pk and throw an exception if it wrong and then catch that exception in a view.
Upvotes: 3