user1595929
user1595929

Reputation: 1372

Override django serializer or models create method

I'm trying to add data to my database. To this purpuse, I have a vue function :

@api_view(['POST'])
  def update_add_bges(request):
    serializer = BGESSerializer(data=request.data)
    if serializer.is_valid():
      serializer.save()
      return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

this one call a serializer to add new data in the database :

class BGESSerializer(serializers.ModelSerializer):    
  laboratoire = LaboratoiresSerializer()

  class Meta:
    model = BGES
    fields = '__all__'

  def create(self, validated_data):
    laboratoire_data = validated_data.pop('laboratoire')
    laboratoire_oj = Laboratoire.objects.create(**laboratoire_data)
    validated_data["laboratoire"] = laboratoire_obj["pk"]
    bges = BGES.objects.create(**validated_data)
    return bges

The problem is that my Laboratoire classe is nested as well, and should add instances from an other class :

class LaboratoiresSerializer(serializers.ModelSerializer):

  tutelles = TutellesSerializer(many=True)

  class Meta:
    model = Laboratoire
    fields = '__all__'

  def create(self, validated_data):
    tutelles_data = validated_data.pop('tutelles')
    laboratoire = Laboratoire.objects.create(**validated_data)
    for tutelle_data in tutelles_data:
      t = Tutelle.objects.get(nom=tutelle_data["nom"])
      laboratoire.tutelles.add(t)
    return laboratoire

This is not working, because not called as it's the create of the serializer and not the create of the Models. How should I do ? When I add a Laboratoire, I have Tutelle to create ... Should I implement the create in the Models ? As I am new to django, I have hard time to understand the subtility of functions calls.

Upvotes: 0

Views: 351

Answers (1)

dirkgroten
dirkgroten

Reputation: 20682

You are asking to create a writable nested serializer when you have a depth of 2, i.e. two nested serializers. Fortunately, you've already written the code in LaboratoireSerializer that creates the Laboratoire and Tutelle objects based on validated_data, so you can do this:

class BGESSerializer(serializers.ModelSerializer):  

    class Meta:
        model = Laboratoire
        fields = '__all__'
        depth = 2

    def create(self, validated_data):
        laboratoire_data = validated_data.pop('laboratoire')
        laboratoire_obj = LaboratoireSerializer.create(self, laboratoire_data)  # note we don't instantiate the serializer! 
        validated_data["laboratoire"] = laboratoire_obj  # note we pass the object not pk
        bges = BGES.objects.create(**validated_data)
        return bges

The trick here is to call the method create on the class, passing self into it. It works because the create method doesn't actually care about self and doesn't use it. I wouldn't work if self was used in the create method of LaboratoireSerializer and expected to be a LaboratoireSerializer. It's hacky, I know, but it works.

Upvotes: 1

Related Questions