DRF: Сериализатор для различных наборов запросов

У меня есть следующий сериализатор

class VoteBaseSerializer(serializers.Serializer):
likes = serializers.IntegerField()
dislikes = serializers.IntegerField()
is_voted = serializers.SerializerMethodField()

def get_is_voted(self, obj):
    user = self.context.get('request').user
    vote = None
    if user.id:
        try:
            vote = Vote.objects.get(pk=obj.pk, user_id=user.id).choice
        except Vote.DoesNotExist:
            pass
    return vote

Моя проблема в том, что я хочу использовать этот сериализатор для различных представлений.

  1. У меня есть представление, которое возвращает статью с prefetch_relted комментариями, затем я аннотирую likes, dislikes и is_voted

    .
  2. У меня есть представление, которое обновляет объект vote. И я хочу вернуть новое условие.

Проблема в SerializerMethodField, когда я пытаюсь получить объект голосования

В 1 случае я работаю с объектом post и комментарием, затем с помощью обратной связи я получаю голоса

В двух случаях я обновляю голосование по comment_id и там разные поиски

Так в 1 случае я получил объект Comment, а во 2 случае я получил объект Vote

models.py

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    slug = models.SlugField(blank=True)
    body = models.TextField()
    tags = TaggableManager(blank=True)
    pub_date = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-pub_date']


class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE,
                             related_name='comments')
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    text = models.TextField(max_length=500)
    pub_date = models.DateTimeField(auto_now=True)
    parent = models.ForeignKey('self', blank=True, null=True,
                               on_delete=models.CASCADE, related_name='children')

    class Meta:
        ordering = ['-pub_date']


class Vote(models.Model):
    comment = models.ForeignKey(Comment, on_delete=models.CASCADE,
                                related_name='votes')
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    choice = models.BooleanField(null=True)

views.py

class PostViewSet(viewsets.ModelViewSet):
serializer_class = PostSerializer
permission_classes = [IsOwnerOrAdminOrReadOnly]
pagination_class = PostPagination
lookup_field = 'slug'

def get_queryset(self):
    likes = Count('votes', filter=Q(votes__choice=True))
    dislikes = Count('votes', filter=Q(votes__choice=False))

    queryset = Post.objects.all().prefetch_related(
        Prefetch('comments', queryset=Comment.objects.filter(parent__isnull=True).order_by('-pub_date')
                 .annotate(likes=likes, dislikes=dislikes)
                 .prefetch_related(Prefetch('children', queryset=Comment.objects.all()
                                            .annotate(likes=likes, dislikes=dislikes)))))

    return queryset

def get_serializer_class(self):
    """"
    Attach related comments
    when get post detail
    """
    if self.action == 'retrieve':
        return PostRetrieveSerializer
    return self.serializer_class

def perform_create(self, serializer):
    serializer.save(author=self.request.user)




class VoteCommentView(generics.UpdateAPIView):
likes = Count('choice', filter=Q(choice=True))
dislikes = Count('choice', filter=Q(choice=False))
queryset = Vote.objects.all().annotate(likes=likes, dislikes=dislikes)

serializer_class = VoteSerializer
permission_classes = [IsAuthenticated]

def get_object(self):
    comment_id = self.kwargs.get('pk')
    try:
        Comment.objects.get(pk=comment_id)
    except Comment.DoesNotExist:
        raise Http404
    obj, created = Vote.objects.get_or_create(user=self.request.user,
                                              comment_id=comment_id
                                              )
    return obj

def perform_update(self, serializer):
    obj = self.get_object()
    action = serializer.validated_data['choice']
    choice = None

    if obj.choice != action:
        choice = action

    serializer.save(choice=choice)

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

    serializer_context = {'request': request}
    obj = self.get_object()
    likes = Count('choice', filter=Q(choice=True))
    dislikes = Count('choice', filter=Q(choice=False))
    qs = Vote.objects.annotate(likes=likes, dislikes=dislikes).get(pk=obj.pk)
    serializer = VoteBaseSerializer(qs, context=serializer_context)
    return Response(serializer.data)
Вернуться на верх