django-rest-framework - 姜戈休息。为嵌套对象列表创建自定义验证错误响应,必须返回无效值列表
问题描述
对不起,这太长了。
我用于创建 Item 对象的端点接收以下 json:
{
"items_data": [
{
"item_id": 1,
"item_name": "Foo",
"item_quantity": 15
},
{
"item_id": 2,
"item_name": "Bar",
"item_quantity": 100
}
]
}
我需要从嵌套列表中创建几个对象,以防验证错误(在任何字段中),响应必须是未验证 ID 的列表(来自 item_id)。
例如,对于这样的请求(“item_id”和“item_quantity”中的字符串):
{
"items_data": [
{
"item_id": "Baz",
"item_name": "Bar",
"item_quantity": 555
},
{
"item_id": 17,
"item_name": "FooBar",
"item_quantity": "many"
}
]
}
答案必须是这样的:
{
"errors":
[
{"id": "Baz"},
{"id": 17}
]
}
为此,我重写了 ItemCreateSerializer 中的 to_internal_value 方法。如果出现验证错误,我会捕获异常,并引发一个新的 ValidationError 以添加有关失败验证的 id 的数据。
def to_internal_value(self, data):
try:
ret = super().to_internal_value(data)
except ValidationError:
raise ValidationError({'id': data['item_id']})
return ret
当我通过邮递员进行测试时,响应正文看起来不错。但是当我运行 django 测试时,它返回一个错误。
问题:
我做的是正确的事,还是可以做不同的事?
如何从响应中删除 ErrorDetail,只得到一个字符串?
测试错误:
self.assertEqual(response.data, {"errors": [{"id": "Baz"}, {"id": 17}]})
AssertionError: {'errors': [{'id': ErrorDetail(string='Baz', code='invalid')[48 chars]')}]} != {'errors': [{'id': 'Baz'}, {'id': 17}]}
我的观点:
class ItemsViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemDataSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
self.perform_create(serializer)
return Response(
serializer.data,
status=status.HTTP_201_CREATED
)
print(serializer.errors)
# Delete empty error dicts from list
error_response = [error_id for error_id in
serializer.errors['items_data'] if error_id]
return Response(
{'errors': error_response},
status=status.HTTP_400_BAD_REQUEST
)
我的商品型号:
class Item(models.Model):
id = models.PositiveIntegerField(primary_key=True)
name = models.CharField(max_length=100)
quantity = models.PositiveIntegerField(default=0)
模型和输入数据中的字段名称不同,所以我的序列化器:
class ItemCreateSerializer(serializers.ModelSerializer):
item_id = serializers.IntegerField(
min_value=1,
write_only=True,
source='id',
)
item_name = serializers.CharField(
source='name',
write_only=True,
)
item_quantity = serializers.IntegerField(
required=True,
min_value=1,
write_only=True,
source='quantity'
)
class Meta:
model = Item
fields = ('item_id', 'item_name', 'item_quantity', 'id')
extra_kwargs = {
'id': {'read_only': True},
}
def to_internal_value(self, data):
try:
ret = super().to_internal_value(data)
except ValidationError as exc:
print(exc)
raise ValidationError({'id': data['item_id']})
return ret
class ItemDataSerializer(serializers.Serializer):
items_data = ItemCreateSerializer(many=True)
class Meta:
fields = ('items_data',)
def create(self, validated_data):
items = validated_data.pop('items_data')
created_items = (Item.objects.create(**item_data) for item_data in items)
return {'items_data': created_items}
解决方案
推荐阅读
- django - 如何在 Django Rest Framework 中使用 models.py 中定义的用户模型进行身份验证
- python - Apscheduler cron 触发器未运行
- javascript - 嵌入上的 Discord.js 代码块格式
- .htaccess - 未找到 Ads.txt - 为 https 重定向正确配置 htaccess
- python - Python、多处理和内存:它是如何工作的?
- java - android studio - 如何停止可运行?
- r - 正则表达式匹配 R 中的日期
- java - 如何在android中获取桌面版网站的内容?
- css - 用户菜单导航背景颜色的 CSS 代码
- git - 如何从`git reset --hard`恢复我上次修改的提交?