: purchased_products = validated_data.pop("products") KeyError: 'products'
我在产品和采购之间有M2M关系。我试图实现的是,当进行购买时,还要填写PurchasedProduct(直通模型)模型。但每次我将数据发送到API,并尝试从validate_data访问序列化程序中的products
密钥时,都会抛出keyError异常,但如果我返回validate_date用于调试product
密钥,则响应是其中的一部分。
djangorestframework==3.11.0
django==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=True
read_only=False
。我还试图在产品模型上抑制uniqueValidator,但仍然不起作用。
经过一点谷歌搜索和一些尝试和错误。我找到了两种解决这个问题的方法。
- 第一种是直接从
self.context
中获取密钥
purchased_products = self.context['request'].data['products']
而且效果很好。但我仍然不明白为什么当试图从validated_data
获得products
时,它会抛出KeyError
。
- 第二个选项是使用嵌套的drf。向队员们大声呼喊
该包为您的序列化程序提供了.create()
和.update()
以及更多的实现,最重要的是它们支持M2M
与through
模型的关系。他们的实现示例