我需要一个类似这样的序列化器:
{
"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。
答案 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)