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
Моя проблема в том, что я хочу использовать этот сериализатор для различных представлений.
У меня есть представление, которое возвращает статью с prefetch_relted комментариями, затем я аннотирую likes, dislikes и is_voted
.У меня есть представление, которое обновляет объект 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)