Корректный способ структурирования моделей, представлений и сериализаторов
У меня есть следующая структура моделей Parent и Child, где ребенок ссылается на родителя.
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)
Я хотел бы, чтобы ParentSerializer.children
включал только объекты ChildModel
с created_by
в качестве self.request.user
.
Какой правильный способ фильтрации ParentSerializer.children
для текущего пользователя?
Я также открыт для изменения моделей.
Сначала я думаю, что у вас есть проблема n+1 в вашем коде.
Когда DRF будет сериализовать ParentModel, обращение к current_parent.children.all()
будет производить SQL запрос для каждого родителя.
Чтобы предотвратить это, вы можете использовать prefetch_related
class ParentViewSet(viewsets.ModelViewSet):
serializer_class = ParentSerializer
queryset = ParentModel.objects.prefetch_related(Prefetch("children"))
В результате будет выполнено 2 SQL-запроса вместо N+1 (где N - количество строк ParentModel).
Дополнительно вы можете использовать prefetch_related
для фильтрации связанной модели:
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)))
Это то, что вы ищете, я думаю