如何在 Django REST 框架中序列化'object list'



我需要这样的序列化程序:

{
    "items": {
        12: {
            "name": "item 1"
        },
        66: {
            "name": "item 2"
        }
    }
}

我应该如何声明我的序列化程序才能获得这样的东西?这甚至是一个有效的 JSON 还是应该看起来像这样:

{
    "items": [
        {
            "name": "item 1",
            "id": 12
        }, {
            "name": "item 2"
            "id": 66
        }
    ]
}

?(12, 66 是这些"项目"的主键)使用 Django REST Framework 3。

在 django rest 框架 3 中有一个 ListField,你可以在这里查看文档 http://www.django-rest-framework.org/api-guide/fields/#listfield

对于您的示例,您可以执行以下操作:

class ItemSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()
class ItemsSerializer(serializers.Serializer):
    items = serializers.ListField(child=ItemSerializer())

后面的序列化程序还可以是:

class ItemsSerializer(serializers.Serializer):
    items = ItemSerializer(many=True)

这样做了那种列表,在文档中是dicts的,但在db中是lists的,在你的示例中你使用整数作为键,你需要使用字符串来符合JSON标准。


from collections import OrderedDict
from django.core.exceptions import FieldDoesNotExist
from django.db import models as django_models
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.fields import SkipField
from rest_framework.settings import api_settings
from rest_framework.utils import html

class ObjectListSerializer(serializers.ListSerializer):
    child = None
    many = True
    default_error_messages = {
        'not_a_dict': _('Expected a dict of items but got type "{input_type}".'),
        'empty': _('This dict may not be empty.')
    }
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if not hasattr(self, 'index_field') or not self.index_field:
            if 'index_field' in kwargs:
                index_field = kwargs.pop('index_field')
                if index_field in self.child.fields:
                    self.index_field = index_field
                else:
                    raise FieldDoesNotExist(
                        _("Field {field_name} does not exists in {serializer_name}.").format(
                            field_name=index_field,
                            serializer_name=self.child.__class__.__name__
                        )
                    )
            else:
                index_field = None
                serializer_model = self.child.get_model()
                if serializer_model:
                    try:
                        index_field = serializer_model._meta.get_field('pk')
                    except FieldDoesNotExist:
                        try:
                            index_field = serializer_model._meta.get_field('id')
                        except FieldDoesNotExist:
                            pass
                    if index_field:
                        self.index_field = index_field.name
                    else:
                        raise FieldDoesNotExist(
                            _(
                                "Cannot find primary key in {serializer_name}, "
                                "try the argument 'index_field' in {my_name}."
                            ).format(
                                my_name=self.__class__.__name__,
                                serializer_name=self.child.__class__.__name__
                            )
                        )
            if not hasattr(self, 'index_field') or not self.index_field:
                raise FieldDoesNotExist(
                    _("Provide the 'index_field' argument for {serializer_name},").format(
                        serializer_name=self.__class__.__name__
                    )
                )
    def get_initial(self):
        if hasattr(self, 'initial_data'):
            return self.to_representation(self.initial_data)
        return {}
    def to_internal_value(self, data):
        """
        List of dicts of native values <- List of dicts of primitive datatypes.
        """
        if html.is_html_input(data):
            data = html.parse_html_list(data, default=[])
        if not isinstance(data, dict):
            message = self.error_messages['not_a_dict'].format(
                input_type=type(data).__name__
            )
            raise ValidationError({
                api_settings.NON_FIELD_ERRORS_KEY: [message]
            }, code='not_a_list')
        if not self.allow_empty and len(data) == 0:
            if self.parent and self.partial:
                raise SkipField()
            message = self.error_messages['empty']
            raise ValidationError({
                api_settings.NON_FIELD_ERRORS_KEY: [message]
            }, code='empty')
        ret = []
        errors = []
        for index_value, item in data.items():
            item[self.index_field] = index_value
            try:
                validated = self.child.run_validation(item)
            except ValidationError as exc:
                errors.append(exc.detail)
            else:
                ret.append(validated)
                errors.append({})
        if any(errors):
            raise ValidationError(errors)
        return ret
    def to_representation(self, data):
        """
        List of object instances -> List of dicts of primitive datatypes.
        """
        # Dealing with nested relationships, data can be a Manager,
        # so, first get a queryset from the Manager if needed
        iterable = data.all() if isinstance(data, django_models.Manager) else data
        ret = OrderedDict()
        for item in iterable:
            dict_doc = self.child.to_representation(item)
            ret[dict_doc.pop(self.index_field)] = dict_doc
        return ret

您可以使用在类的 init 处index_field参数使用此序列化程序

class ItemSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=64)
    description = serializers.CharField()

class BucketSerializer(Serializer):
    items = ObjectListSerializer(
        child=ItemSerializer,
        index_field='name',
        allow_empty=True
    )

或者,如果要用作list_serializer_class index_field可以使用预定义的类值扩展类

class ItemsListSerializer(ObjectListSerializer):
    index_field = 'name'
    allow_empty = True

class ItemSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=64)
    description = serializers.CharField()
    class Meta:
        list_serializer_class = ItemListSerializer

class BucketSerializer(serializers.Serializer):
    items = ItemSerializer(many=True, required=False)
不需要

序列化程序。使用基于类的视图可以简化操作:

from rest_framework import views
from rest_framework.response import Response
from django.http import JsonResponse
class ListItems(views.APIView):
    def get(self, request, format=None):
        items = Item.objects.all().values()
        return JsonResponse(list(items), safe=False)

safe=False,永远记住。

最新更新