如何序列化对象列表'在Django REST框架中

时间:2015-01-16 12:08:17

标签: json django django-rest-framework

我需要一个类似这样的序列化器:

{
    "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。

3 个答案:

答案 0 :(得分:8)

django rest framework 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)

答案 1 :(得分:1)

不需要序列化程序。您可以使用基于类的视图做更简单的事情:

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 return JsonResponse(list(items), safe=False)

答案 2 :(得分:0)

这种类型的列表,在文档中是dicts,在数据库中是lists,在您的示例中,您使用整数作为键,需要使用字符串来符合JSON标准。 / p>


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

您可以在类的初始化处使用参数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
    )

或者如果您想用作index_field,则通过使用预定义的类值list_serializer_class扩展类

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)