Johnny Herrera
Johnny Herrera

Reputation: 126

How to make create and retrieve work in the same serializer?

i have a somewhat tangled problem, I have the following models


class ModelA(models.Model):
    name = models.CharField(max_length=64)

class ModelB(models.Model):
    model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE)

and the serializers

class ModelASerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelA
        fields = '__all__'

class ModelBSerializer(serializers.ModelSerializer):
    terminal = ModelASerializer(read_only=True)
    class Meta:
        model = ModelB
        fields = '__all__'

when I want to create a ModelB object including the model_a_id it has 2 responses depending on whether I put the read_only=True or False

I would like that when I try to create via POST in an object of ModelB I only have to send the mode_a_id, but at the same time when I do a GET it returns the serialized data of ModelASerializer in the model_a field. If I put the read_only = True it only works to receive the serialized data in GET, but via POST I cannot assign an id to model_a

in case of read_only=False, I can't assign the id to that object either since it asks me for a dictionary, I imagine to create a new ModelA Object, but I only want to assign one that already exists.

A solution may be to place the serializer with another variable name, but I would really like it to be the same for both POST and GET.

EDIT #1: examples of the json expected

make a GET for a simple view of ModelB object

{
    "model_a" : {
        "id": 1,
        "name" : "foo"
    }
}

and a POST like:

{
    "model_a" :  1
}

that retrive of POST the same json as a GET:

{
    "model_a" : {
        "id": 1,
        "name" : "foo"
    }
}

Upvotes: 0

Views: 293

Answers (1)

Piyush Kumar
Piyush Kumar

Reputation: 191

Just override to_representation() method of your ModelBSerializer like the following.

class ModelASerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelA
        fields = '__all__'

class ModelBSerializer(serializers.ModelSerializer):
    terminal = ModelASerializer(read_only=True)
    class Meta:
        model = ModelB
        fields = '__all__'
    
    def to_representation(self, instance):
        pre_represented_data = super().to_representation(instance)
        pre_represented_data['model_a'] = ModelASerializer(instance.model_a).data
        return pre_represented_data

And if you seriously don't want the id of ModelB in the GET call then just delete the key from pre_represented_data like following.

class ModelASerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelA
        fields = '__all__'

class ModelBSerializer(serializers.ModelSerializer):
    terminal = ModelASerializer(read_only=True)
    class Meta:
        model = ModelB
        fields = '__all__'
    
    def to_representation(self, instance):
        pre_represented_data = super().to_representation(instance)
        pre_represented_data['model_a'] = ModelASerializer(instance.model_a).data
        del pre_represented_data['id']  # deleting id of ModelB
        return pre_represented_data

Upvotes: 1

Related Questions