André Abboud
André Abboud

Reputation: 2040

DRF post request multiple inner serializers

i have three models named Smoker,Switch,Survey i have smoker as foreign key in Switch model and switch as foreign key in Survey model

class Smoker(models.Model):
    first_name = models.CharField(max_length=50, blank=True, null=True)
    last_name = models.CharField(max_length=50, blank=True, null=True)
    mobile = models.IntegerField(null=True, blank=True)
    gender = models.BooleanField(blank=True, null=True)
    age = models.ForeignKey(Age,models.DO_NOTHING,blank=True, null=True)
    occupation = models.ForeignKey(Occupation, models.DO_NOTHING, blank=True, null=True)

class Switch(models.Model):
    time = models.TimeField(blank=True, null=True)
    count_outers = models.IntegerField(blank=True, null=True)
    count_packs = models.IntegerField(blank=True, null=True)
    smoker = models.ForeignKey(Smoker, models.DO_NOTHING, blank=True, null=True)
    new_brand = models.ForeignKey(NewBrand, models.DO_NOTHING, blank=True, null=True)
    new_sku = models.ForeignKey(NewSku, models.DO_NOTHING, blank=True, null=True)

    # def __str__(self):
    #     return self.time.strftime("%H:%M")


class Survey(models.Model):
    user = models.ForeignKey(User, models.DO_NOTHING, blank=True, null=True)
    date = models.DateField(null=True, blank=True)
    bool_switch = models.BooleanField(null=True, blank=True)
    reason = models.ForeignKey(Reason, models.DO_NOTHING, null=True, blank=True)
    shift = models.ForeignKey(ShiftingTime, models.DO_NOTHING, null=True, blank=True)
    current_brand = models.ForeignKey(CurrentBrand, models.DO_NOTHING, null=True, blank=True)
    current_sku = models.ForeignKey(CurrentSku, models.DO_NOTHING, null=True, blank=True)
    pos = models.ForeignKey(Pos, models.DO_NOTHING, null=True, blank=True)
    switch = models.ForeignKey(Switch, models.DO_NOTHING, null=True, blank=True)

and here i have my serializers:

class SmokerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Smoker
        fields = '__all__'

class SwitchSerializer(serializers.ModelSerializer):
    smoker = SmokerSerializer()
    class Meta:
        model = Switch
        fields = '__all__'
        def create(self, validated_data):
           smoker_data = validated_data.pop('smoker', None)
           if smoker_data:
             smoker = Smoker.objects.create(**smoker_data)
             validated_data['smoker'] = smoker
           return Switch.objects.create(**validated_data)

class SurveySerializer(serializers.ModelSerializer):
    switch = SwitchSerializer()

    class Meta:
        model = Survey
        fields = '__all__'
    def create(self, validated_data):

        switch_data = validated_data.pop('switch', None)
        if switch_data:
            switch = Switch.objects.create(**switch_data)
            validated_data['switch'] = switch
        return Survey.objects.create(**validated_data)

and i make a generic for for Creating and listing all the survey

class SurveyCreateAPIView(generics.ListCreateAPIView):
    def get_queryset(self):
        return Survey.objects.all()
    serializer_class = SurveySerializer

for each displayed survey i have to display switch data related to it and inside the switch object i need to display the smoker object inside it so each survey object must look like this

{
        "id": 11,
        "switch": {
            "id": 12,
            "smoker": {
               "firstname":"sami",
               "lastname:"hamad",
               "mobile":"7983832",
               "gender":"0",
               "age":"2",
               "occupation":"2"
          },
            "time": null,
            "count_outers": 5,
            "count_packs": 7,
            "new_brand": 2,
            "new_sku": 2
        },
        "date": "2018-12-08",
        "bool_switch": true,
        "user": 7,
        "reason": 3,
        "shift": 2,
        "current_brand": 6,
        "current_sku": 4,
        "pos": 2
    },

but when i make a POST request it is giving me this error

ValueError at /api/v2/surveysync/ Cannot assign "OrderedDict([('first_name', 'aline'), ('last_name', 'youssef'), ('mobile', 7488483), ('gender', False), ('age', ), ('occupation', )])": "Switch.smoker" must be a "Smoker" instance.

so please help and thank you so much!

Upvotes: 0

Views: 141

Answers (2)

Ken4scholars
Ken4scholars

Reputation: 6296

You're going along the right path but you're saving the switch objects manually instead of allowing the SwitchSerializer do it for you. Same thing with create method in switch serializer. It should be this way:

class SmokerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Smoker
        fields = '__all__'

class SwitchSerializer(serializers.ModelSerializer):
    smoker = SmokerSerializer()
    class Meta:
        model = Switch
        fields = '__all__'
    def create(self, validated_data):
       smoker_data = validated_data.pop('smoker', None)
       if smoker_data:
         serializer = SmokerSerializer(data=smoker_data, context=self.context)
         if serializer.is_valid():    
            validated_data['smoker'] = serializer.save()
       return super().create(validated_data)

class SurveySerializer(serializers.ModelSerializer):
    switch = SwitchSerializer()

    class Meta:
        model = Survey
        fields = '__all__'
    def create(self, validated_data):

        switch_data = validated_data.pop('switch', None)
        if switch_data:
            serializer = SwitchSerializer(data=switch_data, context=self.context)
            if serializer.is_valid():
                validated_data['switch'] = serializer.save()
        return super().create(validated_data)

Upvotes: 1

c6754
c6754

Reputation: 887

In SwitchSerializer you defined the create function as a method of the inner Meta class and not as a member of SwitchSerializer class. Try this

class SwitchSerializer(serializers.ModelSerializer):
    smoker = SmokerSerializer()
    class Meta:
        model = Switch
        fields = '__all__'
    def create(self, validated_data):
       smoker_data = validated_data.pop('smoker', None)
       if smoker_data:
           smoker = Smoker.objects.create(**smoker_data)
           validated_data['smoker'] = smoker
       return Switch.objects.create(**validated_data)

Upvotes: 0

Related Questions