@Unknown672

Как достать kwargs из url в DRF?

Мне нужно создать отметку рейтинга и в поле profile вставить данные из Url (kwargs['user__id'])
Однако у меня не получается

Есть модель:

class Rating(models.Model):
    profile = models.ForeignKey(
        Profile, on_delete=models.CASCADE, related_name="rating", 
        blank=True, null=True
    )
    rating = models.IntegerField()  
    ...


Важная деталь - в модели Profile есть поле user у которого есть id, вот по нему я и ссылаюсь, т.е user__id

Urls:

path('profile/<int:user__id>/rating/add/', views.RatingAdd.as_view()),


Сериализатор:

class RatingSerializer(serializers.ModelSerializer):
    # Рейтинг специалистов

    class Meta:
        model = Rating
        fields = ['rating']

    def create(self, validated_data):
        rating = Rating.objects.create(profile=Profile.objects.get(user__id=self.kwargs['user__id']), **validated_data)
        return rating


И собственно Views

class RatingAdd(generics.CreateAPIView):
    # Отправка оценки специалисту

    queryset = Rating.objects.all()
    serializer_class = serializers.RatingSerializer
    permission_classes = [IsAuthenticated]


В конце всего этого мне выдает ошибку:
'RatingSerializer' object has no attribute 'kwargs'
  • Вопрос задан
  • 3320 просмотров
Решения вопроса 1
@Unknown672 Автор вопроса
Проблема решена, я убрал метод create из сериализатора и переписал View:

class RatingAdd(generics.GenericAPIView):
    # Отправка оценки специалисту

    serializer_class = serializers.RatingSerializer
    permission_classes = [IsAuthenticated]

    def post(self, request, user__id):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save(profile=Profile.objects.get(user__id=self.kwargs['user__id']))

        return Response(serializer.data, status=status.HTTP_201_CREATED)
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@antonksa
Кривоватое решение. Достаточно передать несуществующий id прилетит 500.
Поэтому все первичные ключи нужно валидировать.

class RatingSerializer(serializers.Serializer):
    user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
    rating = serializers.IntegerField(min_value=1, max_value=5)

    def create(self, validated_data):
        user = validated_data['user']
        rating = validated_data['rating']
        profile = Profile.objects.get(user=user)
        rating_obj = Rating.objects.create(profile=profile, rating=rating)
        return rating_obj


А вьюха должна тогда выглядеть так:
class RatingAdd(generics.GenericAPIView):
    serializer_class = serializers.RatingSerializer
    permission_classes = [IsAuthenticated]

    def post(self, request, **kwargs):
        data = request.data.copy()
        data.update({'user': kwargs['userid'}})
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_201_CREATED)


(upd) Сорян, поправил вьюху, т.к. не удалил кусок оригинального кода.

Что до вопроса про kwargs, то непонятно чего вы ждали, ведь это же kwargs ViewSet'a а не сериализера. Тут нужно быть осторожным, но вообще их можно выковырять из контекста, так как ApiView.get_serializer() еще пропихивает в сериализер контекст:
def create(self, validated_data):
    view = self.context.get('view')
    userid = view.kwargs['userid'] if view else None
    if not userid:
        raise NotFound('User with given id does not exist.')
    rating = Rating.objects.create(profile=Profile.objects.get(user__id=userid), **validated_data)
    return rating
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы