Home > front end >  Correct Way to Structure Models, Views and Serializers
Correct Way to Structure Models, Views and Serializers

Time:11-12

I have the following structure of Parent and Child models, where the child references the parent.

class ParentModel(models.Model):
    name = models.CharField(max_length=255)


class ChildModel(models.Model):
    name = models.CharField(max_length=255)
    parent = models.ForeignKey(
        ParentModel, related_name='children', on_delete=models.CASCADE
    )
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)


class ParentSerializer(serializers.ModelSerializer):
    class Meta:
        model = ParentModel
        fields = (
            'name',
            'children',
        )


class ChildSerializer(serializers.ModelSerializer):
    class Meta:
        models = ChildModel
        fields = (
            'name'
        )


class ParentViewSet(viewsets.ModelViewSet):
    serializer_class = ParentSerializer
    queryset = ParentModel.objects.all()


class ChildViewSet(viewsets.ModelViewSet):
    serializer_class = ChildSerializer

    def get_queryset(self):
        user = self.request.user
        return ChildModel.objects.filter(created_by=user)

I would like for ParentSerializer.children to only include the ChildModel objects with created_by as self.request.user.

What is the correct way to filter ParentSerializer.children to the current user?

I am open to changing the models as well.

CodePudding user response:

First i think you got a n 1 issue with your code.
When DRF will serialize ParentModel, accessing current_parent.children.all() will produce an SQL query for each parent.
To prevent this you can use prefetch_related

class ParentViewSet(viewsets.ModelViewSet):
    serializer_class = ParentSerializer
    queryset = ParentModel.objects.prefetch_related(Prefetch("children"))

This will result in 2 SQL queries instead of N 1 (with N being the number of ParentModel row).

Additionnaly you can use prefetch_related to filter the related model:

class ParentViewSet(viewsets.ModelViewSet):
    serializer_class = ParentSerializer

    def get_queryset(self):
        user = self.request.user
        return ParentModel.objects.prefetch_related(Prefetch("children", queryset=ChildrenModel.objects.filter(created_by=user)))

Which is what you are looking for i think

  • Related