在返回到Response(serializer.data, status=something)
之前,尝试访问serializer.data
时出现错误:
Getting KeyError when attempting to get a value for field
<field>
on serializer<serializer>
.
这发生在所有字段上(因为我试图访问父字段而不是子字段上的.data
,请参见下文)
类定义如下:
class BulkProductSerializer(serializers.ModelSerializer):
list_serializer_class = CustomProductListSerializer
user = serializers.CharField(source='fk_user.username', read_only=False)
class Meta:
model = Product
fields = (
'user',
'uuid',
'product_code',
...,
)
CustomProductListSerializer
是一个serializers.ListSerializer
,并且有一个重写的save()
方法,允许它正确地处理批量创建和更新。
以下是批量产品ViewSet
的示例视图:
def partial_update(self, request):
serializer = self.get_serializer(data=request.data,
many=isinstance(request.data, list),
partial=True)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.save()
pdb.set_trace()
return Response(serializer.data, status=status.HTTP_200_OK)
试图访问跟踪(或者后面的行)处的serializer.data
会导致错误。下面是完整的跟踪(tl;dr skip,下面是我用调试器诊断的地方):
Traceback (most recent call last):
File "/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/lib/python3.5/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
response = self._get_response(request)
File "/lib/python3.5/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/lib/python3.5/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/lib/python3.5/site-packages/rest_framework/viewsets.py", line 86, in view
return self.dispatch(request, *args, **kwargs)
File "/lib/python3.5/site-packages/rest_framework/views.py", line 489, in dispatch
response = self.handle_exception(exc)
File "/lib/python3.5/site-packages/rest_framework/views.py", line 449, in handle_exception
self.raise_uncaught_exception(exc)
File "/lib/python3.5/site-packages/rest_framework/views.py", line 486, in dispatch
response = handler(request, *args, **kwargs)
File "/application/siop/views/API/product.py", line 184, in partial_update
return Response(serializer.data, status=status.HTTP_200_OK)
File "/lib/python3.5/site-packages/rest_framework/serializers.py", line 739, in data
ret = super(ListSerializer, self).data
File "/lib/python3.5/site-packages/rest_framework/serializers.py", line 265, in data
self._data = self.to_representation(self.validated_data)
File "/lib/python3.5/site-packages/rest_framework/serializers.py", line 657, in to_representation
self.child.to_representation(item) for item in iterable
File "/lib/python3.5/site-packages/rest_framework/serializers.py", line 657, in <listcomp>
self.child.to_representation(item) for item in iterable
File "/lib/python3.5/site-packages/rest_framework/serializers.py", line 488, in to_representation
attribute = field.get_attribute(instance)
File "/lib/python3.5/site-packages/rest_framework/fields.py", line 464, in get_attribute
raise type(exc)(msg)
KeyError: "Got KeyError when attempting to get a value for field `user` on serializer `BulkProductSerializer`.\nThe serializer field might be named incorrectly and not match any attribute or key on the `OrderedDict` instance.\nOriginal exception text was: 'fk_user'."
在回溯的L657处(source here))我得到:
iterable = data.all() if isinstance(data, models.Manager) else data
return [
self.child.to_representation(item) for item in iterable
]
这使我想知道(进一步深入跟踪)为什么serializer.fields不可用。我怀疑这是因为序列化程序是一个CustomProductListSerializer
父对象,而不是BulkProductSerializer
子对象,我是对的。在返回Response(serializer.data)
之前的pdb跟踪中:
(Pdb) serializer.fields
*** AttributeError: 'CustomProductListSerializer' object has no attribute 'fields'
(Pdb) serializer.child.fields
{'uuid': UUIDField(read_only=False, required=False, validators=[]) ...(etc)}
(Pdb) 'user' in serializer.child.fields
True
(Pdb) serializer.data
*** KeyError: "Got KeyError when attempting to get a value for field `user` on serializer `BulkProductSerializer`.\nThe serializer field might be named incorrectly and not match any attribute or key on the `OrderedDict` instance.\nOriginal exception text was: 'fk_user'."
(Pdb) serializer.child.data
{'uuid': '08ec13c0-ab6c-45d4-89ab-400019874c63', ...(etc)}
好的,那么在我的ViewSet
中描述的情况下,正确的方法是获取完整的serializer.data
,并在父序列化程序类的resopnse中返回它?
编辑:
class CustomProductListSerializer(serializers.ListSerializer):
def save(self):
instances = []
result = []
pdb.set_trace()
for obj in self.validated_data:
uuid = obj.get('uuid', None)
if uuid:
instance = get_object_or_404(Product, uuid=uuid)
# Specify which fields to update, otherwise save() tries to SQL SET all fields.
# Gotcha: remove the primary key, because update_fields will throw exception.
# see https://stackoverflow.com/a/45494046
update_fields = [k for k,v in obj.items() if k != 'uuid']
for k, v in obj.items():
if k != 'uuid':
setattr(instance, k, v)
instance.save(update_fields=update_fields)
result.append(instance)
else:
instances.append(Product(**obj))
if len(instances) > 0:
Product.objects.bulk_create(instances)
result += instances
return result
如注释中所述,我仍然认为异常可能是由于BulkProductSerializer类中的user字段造成的,实际上与
ListSerializer
无关文档here中提到的序列化程序DRF中可能还有另一个小错误(但很重要)。下面是如何指定
list_serializer_class
:注意,它是在
Meta
类内部指定的,而不是外部指定的。所以我认为在您的代码中,使用many=True
切换到列表序列化程序是不理解的。这会导致不更新问题。Update-添加用于更新嵌套列表序列化程序的示例
似乎问题更多的是关于实现嵌套列表序列化器更新的通用方法,而不是实际的错误。因此,我将尝试提供一个示例代码。
一些注释:
很简单
作为参考,模型如下:
步骤1:确保序列化程序更改为列表序列化程序
步骤2:通过重写create函数来实现ListSerializer
您的错误与
ListSerializer
无关,但获取字段user
时出现问题:确保您的
Product
模型有一个fk_user
字段。您还将
BulkProductSerializer
上的user
字段定义为可写,但尚未告诉序列化程序如何处理它。。。最简单的方法是使用SlugRelatedField:
这应该能很好地处理错误,例如当
username
不存在时。。。在我试图访问
serializer.data
并获取KeyError的跟踪中,我注意到serializer.data
只包含initial_data
中的key/vaule对,而不包含实例数据(因此,我假设KeyError;某些模型字段的key不存在,因为它是一个partial_update
请求)。但是,serializer.child.data
包含列表中最后一个子项的所有实例数据。所以,我转到定义} source :
data
的^{第265行有问题。我可以通过在断点处调用
serializer.child.to_representation({'uuid': '87956604-fbcb-4244-bda3-9e39075d510a', 'product_code': 'foobar'})
来复制错误。调用
partial_update()
在单个实例上工作正常(因为self.instance
已设置,self.to_representation(self.instance)
工作正常)。但是,对于批量部分更新()实现,self.validated_data
缺少模型字段,to_representation()
将无法工作,因此我将无法访问.data
属性。一种选择是维护某种类型的产品实例列表,并在第265行重写
data
的定义:不过,我真的更喜欢有经验的人回答这类问题,因为我不确定这是否是一个明智的解决方案,因此我将悬赏金留空,希望有人能建议一些更明智的做法。
相关问题 更多 >
编程相关推荐