Problem in showing foreign key relation in view

36 Views Asked by At

I have a Land model with three relation which one of them is Letter and the model is:

class Letter(models.Model):
    land = models.ForeignKey('Land', on_delete=models.DO_NOTHING)
    image = models.ImageField(null=True, upload_to=letter_image_file_path)
    text = models.TextField(null=True, blank=True)

def __str__(self):
    return str(self.id)

and its serializer is

class LettersSerializer(serializers.ModelSerializer):

class Meta:
    model = Letter
    fields = ('id', 'text', 'image', 'land',)
    read_only_fields = ('id',)

and Land serializer is:

class LandSerializer(serializers.ModelSerializer):

    utm_points = UTMPointsSerializer(many=True, read_only=True)
    letters = LettersSerializer(many=True, read_only=True)

their views are :

class BasicViewSet(viewsets.ModelViewSet):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)


class LandViewSet(BasicViewSet):
    serializer_class = LandSerializer
    queryset = Land.objects.all()

class UTMPointViewSet(BasicViewSet):
    serializer_class = UTMPointsSerializer
    queryset = UTMPoint.objects.all()


class LettersViewSet(BasicViewSet):
    serializer_class = LettersSerializer
    queryset = Letter.objects.all()

but when I send GET request it doesn't show letters field: here is the response:

{
    "id": 1,
    "utm_points": []
}

although utm_points and letters are exactly the same but they have different results. Land model has user relation which I removed it as simplicity. After some trials and errors I have no idea why the result does't have letters field.

1

There are 1 best solutions below

9
On

You need to explain to the LetterSerializer what serializer to use to serialize Land. You can not use the LandSerializer since that would create a circular dependency but more important: possibly infinite recursion in the response since a Letter has a land and the land then serializes its related letters, etc.

We thus make a simple serializer for Land:

class SimpleLandSerializer(serializers.ModelSerializer):
    utm_points = UTMPointsSerializer(many=True, read_only=True)

    class Meta:
        model = Land
        fields = ['utm_points']

and then use this in the serializer for land:

class LettersSerializer(serializers.ModelSerializer):
    land = SimpleLandSerializer()

    class Meta:
        model = Letter
        fields = ('id', 'text', 'image', 'land',)
        read_only_fields = ('id',)

EDIT: You can also serialize by using the primary key, in that case you can serialize with a PrimaryKeyRelatedField [drf-doc]:

class LettersSerializer(serializers.ModelSerializer):
    land = PrimaryKeyRelatedField()

    class Meta:
        model = Letter
        fields = ('id', 'text', 'image', 'land',)
        read_only_fields = ('id',)

EDIT 2: Another problem is that your letters relation does not exists, if you want to rename the relation from letter_set to letters, you use:

class Letter(models.Model):
    land = models.ForeignKey(
        'Land',
        related_name='letters',
        on_delete=models.DO_NOTHING
    )