Search code examples
djangodjango-rest-frameworkdjango-serializerrest

how to post a model with a foreignkey using django rest framework with only one field?


I'm working on an API, django rest framework for the backend and react on the frontend. i only want to create a model and pass the foreignkey as a dropdown like in django rest framework but with reactjs i have many models the ones without foreignkeys are esly manipulated but i have some models with foreignkeys that i can get but can't POST even with postman i get:

"name": [
        "This field is required."
    ]

i have seen many posts that has same issues but didn't understant gow to implement it here is a simple model with a foreign key

models.py

class SalleSport(models.Model):
    name    = models.CharField( max_length=50)
    adresse = models.CharField( max_length=50)

class Planning(models.Model):
    name            = models.CharField(max_length=50)
    salle_sport     = models.ForeignKey(SalleSport, verbose_name="Salle de sport", on_delete=    
models.CASCADE, null=True, blank=True)

serializers.py

class SalleSportSerialiser(serializers.ModelSerializer):
    class Meta:
        model = SalleSport
        fields= '__all__'

as i want to create a Planning instance i tried many solution that didn't worked i'm gona put them as comments

class PlanningSerialiser(serializers.ModelSerializer):
    # salle_sport = SalleSportSerialiser(read_only=False)

    class Meta:
        model = Planning
        fields= '__all__'
        # fields= ('id', 'name', 'salle_sport')

    # def create(self, validated_data):
    #     salle_sport = validated_data.pop('salle_sport', None)
    #     if author_data:
    #         salle_sport = SalleSport.objects.get_or_create(**salle_sport)[0]
    #         print('salle de sport',salle_sport)
    #         validated_data['salle_sport'] = salle_sport
    #     return Planning.objects.create(**validated_data)


    # def create(self, validated_data):
    #     return Planning.objects.create(**validated_data)

    # def to_representation(self, instance):
    #     # response = super(PlanningSerialiser, self).to_representation(instance)
    #     self.fields["salle_sport"] = SalleSportSerialiser(read_only=True)
    #     return super(PlanningSerialiser, self).to_representation(instance)


    # def get_salle_sport(self, obj):
    #     return SalleSportSerialiser(instance=obj.salle_sport).data

i also tried to implement it on the views.py by over writing the create()

class PlanningAPIView(generics.CreateAPIView):
    queryset = Planning.objects.all()
    serializer_class = PlanningSerialiser

    # def create(self, request):
    #     salle_sport = get_object_or_404(SalleSport, name=request.data.get('salle_sport'))
    #     serializer = self.get_serializer(data= request.data)
    #     serializer.is_valid(raise_exception=True)
    #     serializer.save(salle_sport=salle_sport)
    #     headers = self.get_success_headers(serializer.data)

    #     return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

i have read the documentation about nested serializers but i didn't know how to get it work.


Solution

  • I found the solution, here it is i had to provide one serializer to write and the other to read to get all i want :

    this serializer is to get the SalleSport by names and use it to read

    class NameSalleSportSerialiser(serializers.ModelSerializer):
     
        class Meta:
            model = SalleSport
            fields= ('name',)
    
    
    
    class PlanningListSerialiser(serializers.ModelSerializer):
        salle_sport = NameSalleSportSerialiser()
        class Meta:
            model = Planning
            fields= ('name', 'salle_sport')
    

    this is the serializer that i used to create the nested Model ( with Foreignkey )

    class PlanningSerialiser(serializers.ModelSerializer):
        salle_id = serializers.PrimaryKeyRelatedField(queryset= SalleSport.objects.all(), source='salle_sport.id')
        class Meta:
            model = Planning
    
            fields= ('name', 'salle_id')
     
    
        def create(self, validated_data):
           
            plan = Planning.objects.create(salle_sport=validated_data['salle_sport']['id'], name=validated_data['name'])
    
            return plan
    

    and in React side i fetched made tow request one GET to retreive all SalleSport instance that displays the names but post the ID and like this the user sees the names.