Django Rest Framework:如何在反序列化过程中构建嵌套对象



我有三种型号:

class Customer(models.Model):
name = models.CharField(max_length=30)
class Order(models.Model):
customer = models.ForeignKey(Customer,on_delete=models.CASCADE)
class LineItem(models.Model):
order = models.ForeignKey(Order,on_delete=models.CASCADE)
name = models.CharField(max_length=30)

这是我的测试:

class CreateOrdersTest(APITestCase):
def setUp(self):
self.TEST_SIZE = 10
self.factory = APIRequestFactory()
self._setup_source()
self.data = self._build_data()
def _setup_source(self):
Customer.objects.create(name='test-customer')
def _build_data(self):
return [{'customer':'test-customer','lineitems':[{'name':'apples'},{'name':'oranges'}]} for x in range(self.TEST_SIZE)]
def test_post_orders(self):
request = self.factory.post('/create_orders',self.data)
response = create_orders(request)
response.render()
self.assertEqual(response.status_code,status.HTTP_201_CREATED)

所以post对象看起来像

[{'customer': 'test-customer', 'lineitems': [{'name': 'apples'}, {'name': 'oranges'}]}, .... ] 

以下是序列化程序:

class BulkLineItemSerializer(serializers.ModelSerializer):
def create(self,validated_data):
lineitems = [LineItem(**validated_data) for item in validated_data]
return LineItem.objects.bulk_create(**validated_data)
class LineItemSerializer(serializers.ModelSerializer):
order = ModelObjectidField()
def create(self,validated_data):
return LineItem.objects.create(**validated_data)
class Meta:
model = LineItem
list_serializer_class = BulkLineItemSerializer
fields = ['name','order']
class BulkOrderSerializer(serializers.ListSerializer):
def create(self,validated_data):
orders = [Order(**item) for item in validated_data]
return Order.objects.bulk_create(orders)
class OrderSerializer(serializers.ModelSerializer):
customer = serializers.SlugRelatedField(slug_field='name',queryset=Customer.objects.all())
def create(self,validated_data):
return Order.objects.create(**validated_data)

class Meta:
model = Order
fields = ['customer']
list_serializer_class = BulkOrderSerializer

这是我用于订单对象的ModelObjectidField。

class ModelObjectidField(serializers.Field):
def to_representation(self, value):
return value.id
def to_internal_value(self, data):
return data

因为我像<顺序(1(>,我只是直接返回internal_value。

最后是我的观点。这就是我将行项目与订单进行匹配的方式。

@api_view(['POST'])
def create_orders(request):
if request.method == 'POST':
fixed_orders = []
lineitems_matching = []
offset = 0
lineitems_data = []
for order in request.data:
order_lineitems = order['lineitems']
lineitems_data.extend(order_lineitems)
for item in order_lineitems:
lineitems_matching.append(offset)
offset += 1
fixed_orders.append(order)
orderSerializer = OrderSerializer(data=fixed_orders,many=True)
if orderSerializer.is_valid():
orders = orderSerializer.save()
fixed_lineitems = []
offset = 0
for lineitem_data in lineitems_data:
lineitem_data['order'] = orders[lineitems_matching[offset]]
fixed_lineitems.append(lineitem_data)
offset += 1
lineItemSerializer = LineItemSerializer(data=fixed_lineitems, many=True) # this line is getting the error
if lineItemSerializer.is_valid():
lineItemSerializer.save()
return Response(orderSerializer.data,status=status.HTTP_201_CREATED)
return Response(lineItemSerializer.errors,status=status.HTTP_400_BAD_REQUEST)
return Response(orderSerializer.errors,status=status.HTTP_400_BAD_REQUEST)

目前我得到这个错误:

(venv) alexmarshall@Alexs-MacBook-Pro spicy % ./manage.py test NestedOrderTest
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
E
======================================================================
ERROR: test_post_orders (NestedOrderTest.tests.CreateOrdersTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/alexmarshall/src/GreenData/spicy/spicy/NestedOrderTest/tests.py", line 23, in test_post_orders
response = create_orders(request)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/rest_framework/decorators.py", line 50, in handler
return func(*args, **kwargs)
File "/Users/alexmarshall/src/GreenData/spicy/spicy/NestedOrderTest/views.py", line 31, in create_orders
lineItemSerializer = LineItemSerializer(data=fixed_lineitems, many=True)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 121, in __new__
return cls.many_init(*args, **kwargs)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 158, in many_init
return list_serializer_class(*args, **list_kwargs)
File "/Users/alexmarshall/src/GreenData/spicy/venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 115, in __init__
super().__init__(**kwargs)
TypeError: __init__() got an unexpected keyword argument 'child'
----------------------------------------------------------------------
Ran 1 test in 0.010s
FAILED (errors=1)

我认为问题是我传递的行项目序列化程序数据本身就有顺序。以下是fixed_lineitems数据的样子:

[{'name': 'apples', 'order': <Order: Order object (1)>}, ... ]  

这就是我使用自定义字段的目的,但它似乎不喜欢它?我真的不知道TypeError是什么意思。为什么要生孩子?但实际上,我只是不确定在这种情况下如何设置序列化程序。有什么帮助吗?

编辑:我把行项目序列化程序改成了这个,我相信它能起作用!

class BulkLineItemSerializer(serializers.ListSerializer):
def create(self,validated_data):
lineitems = [LineItem(**item) for item in validated_data]
return LineItem.objects.bulk_create(lineitems)

看看BulkLineItemSerializer,它必须继承自ListSerializer。需要用many=True处理向其传递列表

https://www.django-rest-framework.org/api-guide/serializers/#listserializer

像这样:

class BulkLineItemSerializer(serializers.ListSerializer):
...

最新更新