Используйте разные сериализаторы для ввода и вывода из службы

Ресурс DRF по умолчанию ограничен принятием того же объекта, который он позже возвращает. Я хочу использовать другой сериализатор для ввода, чем вывод. Например, я хочу реализовать регистрацию пользователя, приняв имя пользователя и пароль при возврате нового пользовательского объекта. Можно ли использовать разные сериализаторы для ввода и вывода?

class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

class ImaginarryUserInputSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username', 'password', 'password_confirmation')

class ImaginaryUserOutputSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'registration_date')

Ответ 1

Моя проблема в том, что я хочу иметь разные сериализаторы для ввода и вывода службы.

Достаточно просто иметь разные сериализаторы для разных методов запросов (например, что-то для ответа на запросы GET, отличные от PUT, POST и т.д.)

Просто переопределите get_serializer_class() и верните другой класс сериализатора в зависимости от значения self.request.method.

Это может быть не совсем то, что вы ищете, потому что когда вы укажете PUT или POST, вы все равно получите тот же стиль вывода, что и вы.

В этом случае вы, вероятно, просто должны просто написать представление явно, а не полагаться на стандартные представления по умолчанию, что-то в этом направлении...

class UserCreateOrListView(views.APIView):
    def get(self, request, *args, **kwargs):
        serializer = ImaginaryUserOutputSerializer(User.objects.all())
        return Response(serializer.data)

    def post(self, request, *args, **kwargs):
         serializer = ImaginaryUserInputSerializer(data=request.DATA)
         if serializer.is_valid():
             user = serializer.save()
             output_serializer = ImaginaryUserOutputSerializer(user)
             return Response(output_serializer.data)
         else:
             return Response(serializer.errors, 400)

etc...

Также стоит расспросить список рассылки, поскольку другие пользователи могут делать что-то подобное и иметь полезные шаблоны для совместного использования.

Ответ 2

Одним из решений является TastyPie для Django, который имеет, например.:

  • Resource.alter_deserialized_detail_data() - позволяет вам изменять структуру входящего отдельного ресурса до дальнейшего его интерпретации,
  • Resource.alter_detail_data_to_serialize() - позволяет изменять структуру исходящих одиночных ресурсов до сериализации,

Аналогично верно при сериализации/де-сериализации списков: Resource.alter_deserialized_list_data() и Resource.alter_list_data_to_serialize().

Примечание. Но я считаю, что с Django REST Framework возможно (или будет) нечто подобное. DRF является относительно новым и недавно столкнулся с некоторыми существенными рефакторингами. Django REST Framework имеет довольно хорошее мнение в сообществе Django и, похоже, имеет проницательную команду разработчиков, поэтому, возможно, вам стоит подумать о том, чтобы спросить своих разработчиков или предложить улучшения. Конечно, если вы не найдете никакой помощи по StackOverflow (или встретите ответы от разработчиков DRF здесь).