Django Rest Framework, add an object to request.data, and then call serializer is_valid ()

I am wondering which one is the best to solve, 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, I give the pk serializer. However, I don't want to create a new serializer with PrimaryKeyRelatedField instead of nested relationships just for that. How can I get a PaymentType that matches this pk and then add this object to the request.data dictionary so that is_valid doesn't work? Is this the best way to solve this problem?

+1
django django-rest-framework
source share
1 answer

Suppose payment_type is the ForeignKey field in the ForeignKey model, with null=True due to required=False .
If you provide only pk , so you do not need a serializer for this field, you can simply write in fields , like all other fields.

 class PaymentMethodSerializer(serializers.ModelSerializer): data = serializers.JSONField() class Meta: model = PaymentMethod fields = ('data', 'payment_type') 

He will accept pk or None . If you want to provide a custom presentation for your PaymentType model, you can override the 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 he will use the PaymentTypeSerializer to represent the associated PaymentType model.
You can transfer payment_type check to serializer . Override to_internal_value , check the PaymentType pk provided and throw an exception if it is not, then catch that exception in the view.

+1
source share

All Articles