Фильтрация наборов запросов для вложенных моделей - PullRequest
2 голосов
/ 01 ноября 2019

Я создаю API-интерфейс приложения новостей и хочу создать APIView с комментариями для конкретной публикации, которая также позволяет пользователям публиковать комментарии для конкретной публикации.

Это мои модели (упрощенно):

Сообщение:

class Post(models.Model):
    title = models.CharField(max_length=250)
    text = models.TextField()

Комментарий:

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    author = models.CharField(max_length=200)
    text = models.TextField()

И просмотр:

class CommentList(generics.ListCreateAPIView):
    queryset = Comment.objects.filter(post=???)  
    serializer_class = CommentSerializer

РЕДАКТИРОВАТЬ: Я также хотел бы, чтобы мой URL-путь посмотрелвот так (или подобное):

urlpatterns = [
...
    path('posts/<int:pk>/comments/', CommentList.as_view())
] 

Мои вопросы:

  1. Как мне создать список комментариев для экземпляра Post?
  2. Этоправильный подход или я должен попробовать что-то еще?

Ответы [ 3 ]

0 голосов
/ 02 ноября 2019

Если ваш URL для комментариев выглядит примерно так: / posts / post_id / comments /

# serializer
class CommentSerializer(serializers.ModelSerializer):
    author = SomeAuthorSerializer(read_only=True)

    class Meta:
        model = Comment
        fields = ('author', 'text')

# view
class CommentViewSet(viewsets.GenericViewSet,
                     mixins.CreateModelMixin,
                     mixins.ListModelMixin):
    queryset = Comment.objects
    serializer_class = CommentSerializer

    def initial(self, request, *args, **kwargs):
        super().initial(request, *args, **kwargs)

        try:
            self.post = Post.objects.get(pk=self.request.query_params.get('post_id'))

            # Prefetch post object in this situation let you check permissions
            # eg.:
            if self.post.author != self.request.user:
                raise PermissionDenied()

            # remember that permission classes should be used !

        except Post.DoesNotExist:
            raise NotFound()

    # It will filter your comments
    def filter_queryset(self, queryset):
        queryset = queryset.filter(post=self.post)
        return super().filter_queryset(queryset)

    # It will automatically bypass post object and author 
    # to your serializer create method
    def perform_create(self, serializer):
        serializer.save(post=self.post, author=self.request.user)
0 голосов
/ 02 ноября 2019

Это решение, которое сработало для меня:

class CommentByPostList(generics.ListCreateAPIView):
    queryset = Comment.objects.all()
    serializer_class = CommentListSerializer

    def get_queryset(self):
        return Comment.objects.filter(post=self.kwargs['pk'])
0 голосов
/ 01 ноября 2019

Создайте PostDetailView, чтобы ПОЛУЧИТЬ определенную запись, затем попросите сериализатор вернуть комментарии для этой публикации.

# serializers.py
class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'

class PostSerializer(serializers.ModelSerializer):
    comments = CommentSerializer(many=True)

    class Meta:
        model = Post
        fields = ('title', 'text', 'comments') # Comments field is recognized by the related_name set in your models.

# views.py
class PostDetailView(generics.RetreiveApiView):
    permission_classes = (IsAuthenticated,)
    serializer_class = PostSerializer
    queryset = Post.objects.all()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...