Почему django-rest-frameworks request.data иногда неизменяем? - PullRequest
0 голосов
/ 17 сентября 2018

В моем спокойном CreateAPIView я изменяю свой request.data словарь.

Иногда я получаю сообщение об ошибке, не пойманное моими тестами:

This QueryDict instance is immutable

Например, это:

class CreateView(CreateAPIView):
    serializer_class = ...
    queryset = ...

    def post(self, request, *args, **kwargs):
        request.data['user'] = request.user.pk
        return self.create(request, *args, **kwargs)

request.data кажется нормальным dict в моих тестах. Почему это иногда QueryDict? Как с этим бороться? Должен ли request.data быть мутированным вообще? Как вы должны использовать класс ModelSerializer, когда вам нужно заполнить некоторые поля самостоятельно?

Ответы [ 4 ]

0 голосов
/ 17 сентября 2018

Почему это случайное поведение?

Когда мы смотрим в SC запроса (как упомянул @Kenny Ackerman), он возвращает объект QueryDict, если вы передаете данные типа носителя ('application/x-www-form-urlencoded' или 'multipart/form-data')к классу представления.
Эта проверка выполняется в методе is_form_media_type() класса Request.

Если выпередают данные application/json в представление, request.data будет объектом dict.

Как воспроизвести поведение?

Воспроизвести можно, отправив различные данные ContentType в поле зрения.(В инструменте POSTMAN используйте form-data и raw JSON для получения поведения)


Как получить текущего вошедшего в систему пользователя в сериализаторе?

Method-1 передать дополнительный аргумент .save() (как упомянуто @Linovia) путем переопределения perform_create() метод

class CreateView(CreateAPIView):
    serializer_class = ...
    queryset = ...

    def post(self, request, *args, **kwargs):
        request.data['user'] = request.user.pk
        return self.create(request, *args, **kwargs)

    <b>def perform_create(self, serializer):
        serializer.save(user=self.request.user)</b>

метод-2 Использование CurrentUserDefault() класс, как показано ниже

from django.contrib.auth import get_user_model

User = get_user_model()


class MySerializer(serializers.ModelSerializer):
    <b>user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), default=serializers.CurrentUserDefault())</b>

    class Meta:
    # your code
0 голосов
/ 17 сентября 2018

Когда вам нужно изменить объект QueryDict, полученный из запроса, это неизменный объект, вместо этого используйте эту строку кода, если вы хотите добавить атрибуты:

myNewRequest = request.GET.copy()
myNewRequest.data['some_attr'] = float(something)
0 голосов
/ 17 сентября 2018

Обратите внимание, что это действительно зависит от выбранного вами синтаксического анализатора, указанного в DEFAULT_PARSER_CLASSES rest_framework, и типа содержимого вашего запроса:

JSONParser реализован следующим образом:

return json.load(decoded_stream, parse_constant=parse_constant)

FormParser следующим образом:

return QueryDict(stream.read(), encoding=encoding)
0 голосов
/ 17 сентября 2018

на основе исходного кода . Анализатор возвращает запрос данных, когда поток пустой (request.data вызывает метод _load_data_and_files и _load_data_and_files вызывает метод _parse).

и я думаю, что вы можете заполнить поля, используя HiddenField , или вы можете переопределить метод create или update.например

class TestSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    class Meta:
        model = Test
        fields = ('id', 'text', 'user')

    def create(self, validated_data):

        validated_data['populate_field'] = 'value'
        return super().create(validated_data)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...