Django Rest Framework сериализует объект двумя разными способами, используя один и тот же сериализатор. - PullRequest
0 голосов
/ 05 апреля 2020

При использовании DRF ViewSet и APIView я получаю два разных результата для сериализации DurationField.

На первой конечной точке хоста / приложения / items, которая соответствует viewset Items и перечисляет все из созданных элементов я получаю этот ответ:

[
    {
        "id": 2,
        "duration": "604800.0",
        ...
    }
    ...
]

Ответ от host / app / user_data включает в себя элементы, соответствующие экземплярам элемента, которые имеют отношение к профилю:

{
    ...
    "items": [
        {
            "item": {
                "id": 2,
                "duration": "P7DT00H00M00S",
                ...
            }
            ...
        }
    ]
}

Но продолжительность указана в формате ISO 8601 . Это было очень сложно, потому что конечные точки используют один и тот же сериализатор. Я подтвердил это, вызвав сериализацию с помощью duration = serializers.DurationField() в ItemSerializer. Я хочу тот же формат, в секундах. Что я могу сделать?

Это проблемы, которые я обнаружил при исследовании этой проблемы: https://github.com/encode/django-rest-framework/issues/4430 https://github.com/encode/django-rest-framework/issues/4665

URL:

router = routers.DefaultRouter()
router.register(r'items', views.Items)

urlpatterns = [
    path('', include(router.urls)),
    path('user_data', views.UserData.as_view(), name='user_data'),
    ...
]

Просмотры:

class Items(viewsets.ModelViewSet):
    queryset = Item.objects.all()
    serializer_class = ItemSerializer

    def get_permissions(self):
        if self.action in ('list', 'retrieve'):
            permission_classes = [AllowAny]
        else:
            permission_classes = [IsAdminUser]
        return [permission() for permission in permission_classes]


class UserData(APIView):
    """Get authenticated user's information: data related to models User and Profile"""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = request.user
        user_serialized = UserSerializer(user)
        profile_serialized = ProfileSerializer(user.profile)
        user_info = {}
        user_info.update(user_serialized.data)
        user_info.update(profile_serialized.data)
        return JsonResponse(user_info)

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

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = '__all__'
        depth = 1


class ItemInstanceSerializer(serializers.ModelSerializer):
    item = ItemSerializer()

    class Meta:
        model = ItemInstance
        fields = ['item']
        depth = 2


class ProfileSerializer(serializers.ModelSerializer):
    items = ItemInstanceSerializer(source='iteminstance_set', many=True)

    class Meta:
        model = Profile
        fields = ['address', 'birth_date', 'items']

Модели:

class Item(models.Model):
    ...
    SINGLE_DAY = timedelta(days=1)
    WEEK = timedelta(weeks=1)
    MONTH = timedelta(weeks=4)
    YEAR = timedelta(weeks=52)
    DURATION_CHOICES = [
        (SINGLE_DAY, 'Single-day'),
        (WEEK, 'Week'),
        (MONTH, 'Month'),
        (YEAR, 'Year'),
    ]
    duration = models.DurationField(
        choices=DURATION_CHOICES,
    )
    ...


class ItemInstance(models.Model):
    ...
    item = models.ForeignKey(
        Item,
        on_delete=models.CASCADE,
    )
    ...

1 Ответ

0 голосов
/ 05 апреля 2020

Проблема с JSONResponse, используемым в UserData. Он будет использовать сериализацию Django вместо DRF. Вместо этого используйте rest_framework.response.Response. Вы можете буквально изменить это, и это должно работать. Вы также можете удалить строку item = ItemSerializer() из ItemInstanceSerializer, поскольку ItemSerializer не делает ничего особенного. Поля сериализатора по умолчанию в DRF хороши. Они созданы здесь неявно ModelSerializer.

Причина, по которой сериализация отличается, заключается в том, что serializer.data не всегда возвращает обработанные значения (полностью обработанные). Когда вы передадите эту структуру JSONResponse, она будет делать то же самое со значениями, которые не являются JSON дружественными примитивами, тогда как Response делает это по-другому. Согласно документации serializer.data должен возвращать только примитивные типы , но это не относится к timedelta. Свой.

...