I'm trying to write a Django Rest Framework serializer. It is supposed to take in a simple primitive data and return data with some of the related objects data. The model I'm serializing is Model_C
Here are the models:
class ModelA(models.Model):
name = models.Charfield(max_length=16)
attr1 = models...
...
class ModelB(models.Model):
name = models.CharField(max_length=16)
attr1 = models...
...
class ModelC(models.Model):
model_a = models.ForeignKey(ModelA)
model_b = models.ForeignKey(ModelB)
text = models.CharField(max_length=32)
date = models.DateTimeField()
Here is the api view:
class ModelCApiView(RetrieveUpdateDestroyAPIView):
serializer_class = ModelCSerializer
def get_queryset(self):
return self.serializer_class.Meta.model.objects.all()
def post(self, request):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(data=serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
The data fed to the serializer are as follows (with or without the ID):
{'id': '1', 'model_a': 1, 'model_b': 1, 'text': 'some text', 'date': '2019-08-28 08:00:00'}
Now, the thing is that the serializer should save the instance and return the serialized model WITH SOME OF THE related data:
{'id': '1', 'model_a': {'id': 1, 'name': 'some model a name'}, 'model_b': {'id': 1, 'name': 'some model b name', 'attr1': 'some attr value'}, 'text': 'some text', 'date': '2019-08-28 08:00:00'}
So the only thing that is created is ModelC instance. The api view is not supposed to create ModelA or ModelB instances.
The main problem is with serializing/deserializing objects. I already tried several things:
- The most simple
class ModelCSerializer(serializers.ModelSerializer):
class Meta:
model = ModelC
fields = "__all__"
It properly deserializes the request, saves instance, but returns too little information - only IDs of related objects.
- I used depth
class ModelCSerializer(serializers.ModelSerializer):
class Meta:
model = ModelC
fields = "__all__"
depth = 1
This does not work, as it spits out 500 with error: "Column 'model_a_id' cannot be null".
- I tried adding to 2. declared serializers:
class ModelCSerializer(serializers.ModelSerializer):
class Meta:
model = ModelC
fields = "__all__"
depth = 1
model_a = ModelASerializer()
model_b = ModelBSerializer()
This produces error 400, bad request, as it asks me to insert ALL data for model_a and model_b as a dict.
- I added lines to APIView to serialize data with simple serializer, and then serialize again with more advanced and return more info.
serializer = ModelCSerializer
def post(self, request):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
obj = serializer.save()
serializer = ModelCReadOnlySerializer(instance=obj, data=serializer.data)
serializer.is_valid()
return Response(data=serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ModelCReadOnlySerializer(serializers.ModelSerializer):
class Meta:
model = ModelC
fields = ("id", "model_a", "model_b", "text", "date")
read_only_fields = fields
depth = 1
This is the closest to the solution as I have been, since it returns almost what I need, except for that it returns ALL data for model_a and model_b, which is way too much.
At this point I have other ideas, but I bet they're all terrible. I'd be glad on any hints how to proceed, because I'm this close -> || <- to writing everything ny myself without DRF :-)
Thank you in advance.