Ответ
Для кастомизации логики получения одного объекта в ModelViewSet необходимо переопределить его метод retrieve в дочернем классе. Это позволяет добавить дополнительную логику, изменить данные перед отправкой или выполнить проверку прав.
Зачем это может понадобиться:
- Добавить в ответ связанные данные, которые не входят в стандартный сериализатор.
- Увеличить счетчик просмотров объекта.
- Выполнить сложную проверку прав доступа перед отдачей объекта.
Пример: Добавление дополнительного поля в ответ
from rest_framework import viewsets, status
from rest_framework.response import Response
from .models import Article
from .serializers import ArticleSerializer
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def retrieve(self, request, *args, **kwargs):
# 1. Получаем объект стандартным способом
instance = self.get_object()
# 2. Увеличиваем счетчик просмотров (кастомная логика)
instance.views_count += 1
instance.save()
# 3. Сериализуем данные
serializer = self.get_serializer(instance)
data = serializer.data
# 4. Добавляем в ответ дополнительную информацию
data['is_author'] = instance.author == request.user
# 5. Возвращаем кастомизированный Response
return Response(data, status=status.HTTP_200_OK)
Ключевые компоненты:
self.get_object(): Стандартный метод DRF для получения объекта поpkиз URL.self.get_serializer(instance): Получение экземпляра сериализатора для конкретного объекта.Response(data): Стандартный объект ответа DRF, который необходимо вернуть в конце.
Ответ 18+ 🔞
А, ну вот, смотри, смотри! Опять этот твой ModelViewSet, который как будто бы всё умеет, а на деле — нихуя не умеет, если надо что-то своё, нестандартное. Как будто тебе дали машину, а руль прикручен наглухо, только прямо ехать. А если надо в соседний переулок? Вот для этого и нужен метод retrieve.
Зачем это, спрашиваешь? Да похуй, причины могут быть какие угодно! Например, ты хочешь, чтобы при каждом просмотре статьи счётчик подскакивал. Или тебе надо в ответ сунуть какую-нибудь хитрожопую проверку, типа «а ты, сука, автор этой статьи или просто зритель?». Или вообще подгрузить кучу связанных данных, которые в обычный сериализатор не влезли. Короче, когда стандартного поведения — как дохлой кобыле под хвост.
Смотри, как это делается. Берёшь свой вьюсет и просто пишешь свой метод. Главное — не сломать то, что уже работает.
from rest_framework import viewsets, status
from rest_framework.response import Response
from .models import Article
from .serializers import ArticleSerializer
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def retrieve(self, request, *args, **kwargs):
# 1. Получаем объект стандартным способом
instance = self.get_object()
# 2. Увеличиваем счетчик просмотров (кастомная логика)
instance.views_count += 1
instance.save()
# 3. Сериализуем данные
serializer = self.get_serializer(instance)
data = serializer.data
# 4. Добавляем в ответ дополнительную информацию
data['is_author'] = instance.author == request.user
# 5. Возвращаем кастомизированный Response
return Response(data, status=status.HTTP_200_OK)
Вот, видишь? Всё просто, как три копейки. Сначала вытаскиваем объект через self.get_object() — это чтобы не изобретать велосипед и все проверки пермишенов остались. Потом делаем свою магию — в нашем случае накручиваем счётчик. Потом сериализуем, как обычно. А потом — о, смотри, самое интересное! — лепим в ответ какое-нибудь своё поле, например, is_author. И вуаля, в рот меня чих-пых, у тебя кастомный ответ!
Главное — не забудь в конце вернуть Response. А то настолько увлечёшься своей логикой, что забудешь, зачем вообще всё это затеял. И будет тебе вместо статьи — тишина, блядь, и статус 500.