Используйте SerializerMethodField
, чтобы создать поле только для чтения и получить его значение, вызвав метод в классе сериализатора.
Создать поле и метод в сериализаторе с именем get_<field_name>
.Этот метод имеет два аргумента: self
и сериализуемый объект (точно так же, как ваш get_is_liked()
метод)
serializers.py
class BookSerializer(serializers.ModelSerializer):
is_liked = serializers.SerializerMethodField()
likes = serializers.SerializerMethodField()
def get_is_liked(self, obj):
'''
Returns a boolean that represents whether the book has
already been liked by the user
'''
return models.BookLike.objects.filter(
book=obj,
liker=self.context['request'].user
).exists()
def get_likes(self, obj):
'''
Returns the numer of likes of the book
'''
return models.BookLike.objects.filter(book=obj).count()
Реализация конечной точки для Liking
get_is_liked()
всегда будет возвращать False
до тех пор, пока API не позволит пользователю дать оценку книге.Для этого потребуется создать новую конечную точку.
Я предлагаю вам объединить ваши представления в один набор и добавить дополнительное действие (см. документация ) для выполнения аналогичной функции.Что-то вроде:
from rest_framework.decorators import action
class BookViewSet(generics.ModelViewSet):
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
queryset = models.Book.objects.all()
serializer_class = serializers.BookSerializer
@action(methods=['post'], detail=True)
def like(self, request, pk=None):
book = self.get_object()
# Create a like for the book or get an existent one
like, created = BookLike.objects.get_or_create(
book=book,
liker=request.user
)
# User never gave a like for this book
if created:
return Response({
'detail': 'Your like was registered with success.'
})
# Book already liked by the user (dislike or error?)
return Response({
'detail': 'Only one like per book is allowed.'
}, status.HTTP_400_BAD_REQUEST)
urls.py
from rest_framework.routers import DefaultRouter
from django.urls import path, include
from . import views
router = DefaultRouter()
router.register(r'books', views.BookViewSet, base_name='book')
urlpatterns = [
path('', include(router.urls)),
]
При такой конфигурации конечная точка для лайка равна
POST /books/{bookId}/like/