validate_data在.create():嵌套序列化程序中的POST请求验证期间丢弃了一些字段



: purchased_products = validated_data.pop("products") KeyError: 'products'

我在产品和采购之间有M2M关系。我试图实现的是,当进行购买时,还要填写PurchasedProduct(直通模型)模型。但每次我将数据发送到API,并尝试从validate_data访问序列化程序中的products密钥时,都会抛出keyError异常,但如果我返回validate_date用于调试product密钥,则响应是其中的一部分。

djangorestframework==3.11.0django==2.2.10

class Product(Model):
name = CharField(max_length=20, unique=True)
date_added = DateTimeField(default=now)

型号.py

class Purchase(Model):
manager = ForeignKey('users.User', on_delete=PROTECT, related_name='purchases')
quantity = DecimalField(max_digits=6, decimal_places=2)
products = ManyToManyField('branches.Product', through='PurchasedProduct',
through_fields=('purchase', 'product'))
amount_fc = IntegerField(default=0)
amount_usd = IntegerField(default=0)
total_amount = IntegerField(default=0)
date_purchased = DateTimeField(default=now)

class PurchasedProduct(Model):
purchase = ForeignKey('Purchase', on_delete=CASCADE, related_name="to_products", blank=True)
product = ForeignKey('branches.Product', on_delete=CASCADE, related_name='purchases')
unit_price = DecimalField(max_digits=12, decimal_places=4, default=0.00)
quantity = DecimalField(max_digits=5, decimal_places=2)
amount_fc = DecimalField(max_digits=10, decimal_places=2)
date_purchased = DateTimeField(default=now)

serializer.py

class PurchasedProductSerializer(ModelSerializer):
class Meta:
model = PurchasedProduct
fields = [
"id",
"purchase",
"product",
"unit_price",
"quantity",
"amount_fc",
"date_purchased"
]

class PurchaseSerializer(ModelSerializer):
# https://github.com/encode/django-rest-framework/issues/5403
products = PurchasedProductSerializer(source="to_products", many=True)
class Meta:
model = Purchase
fields = [
"id",
"manager",
"quantity",
"amount_fc",
"amount_usd",
"total_amount",
"products",
"date_purchased"
]
def create(self, validated_data):
purchased_products = validated_data.pop("products")
manager = validated_data.pop('manager')
quantity = validated_data.pop('quantity')
amount_fc = validated_data.pop('amount_fc')
amount_usd = validated_data.pop('amount_usd')
total_amount = validated_data.pop('total_amount')
purchase = Purchase.objects.create(
manager=manager,
quantity=quantity,
amount_fc=amount_fc,
amount_usd=amount_usd,
total_amount=total_amount
)
for purchased_product in purchased_products:
product = Product.objects.get(pk=purchased_product.pop("product"))
purchase.products.add(product, through_default=purchased_product)
return purchase

view.py

class PurchasesListView(ListCreateAPIView):
queryset = Purchase.objects.all()
serializer_class = PurchaseSerializer
permission_classes = [AllowAny]
filterset_fields = ['date_purchased', 'manager']

数据

{
"amount_fc": 13303340.0,
"amount_usd": 1500,
"manager": 2,
"quantity": 100,
"total_amount": 1230945,
"products": [
{
"amount_fc": 1200334,
"product": 8,
"quantity": 120, 
"unit_price": 10003.34
},
{
"amount_fc": 1600334,
"product": 6,
"quantity": 100, 
"unit_price": 16003.34
}
]
}

错误:

purchased_products = validated_data.pop("products") KeyError: 'products'

但当我将purchased_products = validated_data.pop("products")更改为purchased_products = validated_data.pop("products", [])时,它可以工作,但不能填充直通模型(PurchasedProduct)

我尝试过的

DRF示例DRF文档示例

drf可写嵌套drf可写嵌套不支持具有直通型的M2M

删除源products = PurchasedProductSerializer(many=True)添加了write_only=Trueread_only=False。我还试图在产品模型上抑制uniqueValidator,但仍然不起作用。

经过一点谷歌搜索和一些尝试和错误。我找到了两种解决这个问题的方法。

  1. 第一种是直接从self.context中获取密钥
purchased_products = self.context['request'].data['products']

而且效果很好。但我仍然不明白为什么当试图从validated_data获得products时,它会抛出KeyError

  1. 第二个选项是使用嵌套的drf。向队员们大声呼喊

该包为您的序列化程序提供了.create().update()以及更多的实现,最重要的是它们支持M2Mthrough模型的关系。他们的实现示例

最新更新