我正在尝试使用ListSerializer
进行批量更新Viewset
.我的批量创建工作正常,但不是 PUT。这是我Serializer
、ListSerizlier
和我的观点。
django=2.0.0
Serializer
class SampleListSerializer(serializers.ListSerializer):
pass
class SampleSerializer(serializers.ModelSerializer):
class Meta:
list_serializer_class = SampleListSerializer
model = Sample
fields = ['id', 'name', 'last_name' ]
这是我的ViewSet
:
class SampleViewSet(viewsets.ModelViewSet):
serializer_class = SampleSerializer
queryset = Sample.objects.all()
def get_serializer(self, *args, **kwargs):
if "data" in kwargs:
data = kwargs["data"]
# check if many is required
if isinstance(data, list):
kwargs["many"] = True
return super(SampleViewSet, self).get_serializer(*args, **kwargs)
def put(self, request):
sorted(request.data, key=lambda o: o["id"])
instances = Sample.objects.filter(id__in=[o["id"] for o in request.data]).order_by("id")
try:
with transaction.atomic():
ss = SampleSerializer(data=request.data, instance=instances, many=True)
if ss.is_valid(raise_exception=True):
s = ss.save()
return Response(ss.data)
return Response(status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
print(f"In exception {e}")
return Response(status=status.HTTP_400_BAD_REQUEST)
def create(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)
我得到的"查询集"对象在ss.is_valid()
没有属性"pk"。有人可以建议我的错误在哪里吗?还是怎么了?
>instance
关键字采用单个 QuerySet 对象,但看起来您正在传递一个"ListQuerySet"(技术上只是一个 QuerySet(。
如果你print(instances)
它将看起来像这样(假设你没有覆盖类的__str__
方法(:
<QuerySet [<Sample: Sample object(1)>, <Sample: Sample object(2)>, ... ]>
在serializers.ModelSerializer
的某处,instance.pk
被调用,这将始终导致:
"QuerySet"对象没有属性"pk">
这里有一个改编的答案:https://github.com/miki725/django-rest-framework-bulk/issues/68
最好的解决方法是 覆盖ListSerializer
上的to_internal_value
.
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)
if not isinstance(data, list):
message = self.error_messages['not_a_list'].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 item in data:
try:
# custom code
self.child.instance = self.instance.get(id=item['id']) if self.instance else None
self.child.initial_data = item
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