在 django rest 框架中创建和更新我的列表时输入错误
Type error to create and update my list in django rest framework
我正在尝试使用我的 api 来创建和更新捆绑包中的产品。我这样做了:
model.py
class Business(models.Model):
name = models.CharField(max_length=155)
class Product(models.Model):
business = models.ForeignKey(
Business,
on_delete=models.CASCADE,
blank=True,
null=True,
)
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
class Meta:
verbose_name = "Product"
class Bundle(models.Model):
business = models.ForeignKey(
Business,
on_delete=models.CASCADE,
blank=True,
null=True,
)
name = models.CharField(max_length=100)
description = models.TextField(null=True, blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
products = models.ManyToManyField(Product, related_name="bundles",blank=True, null=True, through="BundleProduct")
class Meta:
verbose_name = "Bundle"
def __str__(self):
return self.name
class BundleProduct(models.Model):
bundle = models.ForeignKey(Bundle, on_delete=models.CASCADE, related_name="bundleproducts")
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="bundleproducts")
number = models.IntegerField(default=1)
class Meta:
verbose_name = "Bundle of Product"
def __str__(self):
return str(self.product.name) + " do " + self.bundle.name
def get_absolute_url(self):
return reverse("BundleProduct_detail", kwargs={"pk": self.pk})
这是我的 serializers.py:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = "__all__"
class BundleProductSerializer(serializers.ModelSerializer):
class Meta:
model = BundleProduct
fields = "__all__"
class BundleSerializer(serializers.ModelSerializer):
class Meta:
model = Bundle
fields = "__all__"
我的viewset.py
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
model = Product
class BundleProductViewSet(viewsets.ModelViewSet):
queryset = BundleProduct.objects.all()
serializer_class = BundleProductSerializer
model = BundleProduct
class BundleViewSet(viewsets.ModelViewSet):
queryset = Bundle.objects.all()
serializer_class = BundleSerializer
model = Bundle
当我尝试 post 捆绑产品中的某些产品时,我收到了 "Incorrect type. Expected pk value, received list."
阅读此错误后,我发现了一些与 PrimaryKeyRelatedField 和 SlugRelatedField 相关的问题。我知道我需要覆盖,但我不知道该怎么做。
这是 post 如何运作的示例:
{
"number": 1,
"bundle": 2,
"product":
[
1,
2
]
}
看完 Neil 评论的视频后,我创建了以下方法:
class BundleSerializer(
serializers.ModelSerializer
):
products = ProductSerializer(many=True)
def create(self, validated_data):
products = validated_data.pop('products')
bundle = BundleProduct.objects.create(**validated_data)
for product in products:
BundleProduct.objects.create(**product, bundle=bundle)
return Bundle
class Meta:
model = Bundle
fields = "__all__"
但是不起作用。我收到此错误:“TypeError at /api/v1/bundle/
'name' 是此函数的无效关键字参数
根据我的经验,如果你想在一个请求中更新模型和相关模型,使用 DRF,最简单的方法是覆盖序列化程序的 "create" 方法。这里有一个很好的视频,我用作参考:https://www.youtube.com/watch?v=EyMFf9O6E60
这里的问题是您将列表发布到 BundleProduct
的产品字段,但它是 ForeignKey
。要将 Bundle
加入 Product
,只需 POST
:
{
"bundle": 2,
"product" 1,
"number": 1
}
你可以重复这个:
{
"bundle": 2,
"product" 4,
"number": 1
}
将另一个产品 4 添加到同一个捆绑包中,依此类推。只要确保你一个一个地做,而不是像你之前做的那样在列表中做。
如果您通过 BundleSerializer 制作 post,您需要传递带有 ProductSerializer 数据列表的产品,而不仅仅是 id,因为 BundleSerializer 中的产品正在接受 productsSerializer 数据。您收到 类型错误 'name' is an invalid keyword argument for this function because your validated_data contain name and BundleProduct object Does not have name field.And您正在使用 validated_data.
创建 BundleProduct 对象
创建 bundle 对象并将 bundle 对象的 id 传递给 BundleProduct 对象。
如果您不想创建产品而只是传递现有的产品 ID,则需要创建 ListField
您需要覆盖 get_fields 并检查请求
- 将 to_representation 覆盖为 return 总是 ProdutSerializer 数据列表
- 为 POST 请求
覆盖创建
- 为 PUT 和 PATCH 请求
覆盖 更新
下面是 POST 请求
的解决方案
对于PATCH AND PUT 请求您需要覆盖ModelSerializer 的更新方法并相应地处理产品。
class BundleSerializer(serializers.ModelSerializer):
def create(self, validated_data):
products = validated_data.pop('products')
bundle = Bundle.objects.create(**validated_data)
for product_id in products:
product = get_object_or_404(Product, pk=product_id)
BundleProduct.objects.create(product=product, bundle=bundle)
return bundle
class Meta:
model = Bundle
fields = "__all__"
def to_representation(self, instance):
repr = super().to_representation(instance)
repr['products'] = ProductSerializer(instance.products.all(), many=True).data
return repr
def get_fields(self):
fields = super().get_fields()
if self.context['request'].method in ['POST', "PATCH","PUT"]:
fields['products'] = serializers.ListField(
write_only=True,
child=serializers.IntegerField()
)
return fields
将 POST 数据采样到 BundleSerializer
{
"products":[1,2],
"name":"Offer One",
"description":"description",
"price":1212,
"business":1
}
我正在尝试使用我的 api 来创建和更新捆绑包中的产品。我这样做了:
model.py
class Business(models.Model):
name = models.CharField(max_length=155)
class Product(models.Model):
business = models.ForeignKey(
Business,
on_delete=models.CASCADE,
blank=True,
null=True,
)
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
class Meta:
verbose_name = "Product"
class Bundle(models.Model):
business = models.ForeignKey(
Business,
on_delete=models.CASCADE,
blank=True,
null=True,
)
name = models.CharField(max_length=100)
description = models.TextField(null=True, blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
products = models.ManyToManyField(Product, related_name="bundles",blank=True, null=True, through="BundleProduct")
class Meta:
verbose_name = "Bundle"
def __str__(self):
return self.name
class BundleProduct(models.Model):
bundle = models.ForeignKey(Bundle, on_delete=models.CASCADE, related_name="bundleproducts")
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="bundleproducts")
number = models.IntegerField(default=1)
class Meta:
verbose_name = "Bundle of Product"
def __str__(self):
return str(self.product.name) + " do " + self.bundle.name
def get_absolute_url(self):
return reverse("BundleProduct_detail", kwargs={"pk": self.pk})
这是我的 serializers.py:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = "__all__"
class BundleProductSerializer(serializers.ModelSerializer):
class Meta:
model = BundleProduct
fields = "__all__"
class BundleSerializer(serializers.ModelSerializer):
class Meta:
model = Bundle
fields = "__all__"
我的viewset.py
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
model = Product
class BundleProductViewSet(viewsets.ModelViewSet):
queryset = BundleProduct.objects.all()
serializer_class = BundleProductSerializer
model = BundleProduct
class BundleViewSet(viewsets.ModelViewSet):
queryset = Bundle.objects.all()
serializer_class = BundleSerializer
model = Bundle
当我尝试 post 捆绑产品中的某些产品时,我收到了 "Incorrect type. Expected pk value, received list."
阅读此错误后,我发现了一些与 PrimaryKeyRelatedField 和 SlugRelatedField 相关的问题。我知道我需要覆盖,但我不知道该怎么做。
这是 post 如何运作的示例:
{
"number": 1,
"bundle": 2,
"product":
[
1,
2
]
}
看完 Neil 评论的视频后,我创建了以下方法:
class BundleSerializer(
serializers.ModelSerializer
):
products = ProductSerializer(many=True)
def create(self, validated_data):
products = validated_data.pop('products')
bundle = BundleProduct.objects.create(**validated_data)
for product in products:
BundleProduct.objects.create(**product, bundle=bundle)
return Bundle
class Meta:
model = Bundle
fields = "__all__"
但是不起作用。我收到此错误:“TypeError at /api/v1/bundle/
'name' 是此函数的无效关键字参数
根据我的经验,如果你想在一个请求中更新模型和相关模型,使用 DRF,最简单的方法是覆盖序列化程序的 "create" 方法。这里有一个很好的视频,我用作参考:https://www.youtube.com/watch?v=EyMFf9O6E60
这里的问题是您将列表发布到 BundleProduct
的产品字段,但它是 ForeignKey
。要将 Bundle
加入 Product
,只需 POST
:
{
"bundle": 2,
"product" 1,
"number": 1
}
你可以重复这个:
{
"bundle": 2,
"product" 4,
"number": 1
}
将另一个产品 4 添加到同一个捆绑包中,依此类推。只要确保你一个一个地做,而不是像你之前做的那样在列表中做。
如果您通过 BundleSerializer 制作 post,您需要传递带有 ProductSerializer 数据列表的产品,而不仅仅是 id,因为 BundleSerializer 中的产品正在接受 productsSerializer 数据。您收到 类型错误 'name' is an invalid keyword argument for this function because your validated_data contain name and BundleProduct object Does not have name field.And您正在使用 validated_data.
创建 BundleProduct 对象创建 bundle 对象并将 bundle 对象的 id 传递给 BundleProduct 对象。
如果您不想创建产品而只是传递现有的产品 ID,则需要创建 ListField
您需要覆盖 get_fields 并检查请求
- 将 to_representation 覆盖为 return 总是 ProdutSerializer 数据列表
- 为 POST 请求 覆盖创建
- 为 PUT 和 PATCH 请求 覆盖 更新
下面是 POST 请求
的解决方案对于PATCH AND PUT 请求您需要覆盖ModelSerializer 的更新方法并相应地处理产品。
class BundleSerializer(serializers.ModelSerializer):
def create(self, validated_data):
products = validated_data.pop('products')
bundle = Bundle.objects.create(**validated_data)
for product_id in products:
product = get_object_or_404(Product, pk=product_id)
BundleProduct.objects.create(product=product, bundle=bundle)
return bundle
class Meta:
model = Bundle
fields = "__all__"
def to_representation(self, instance):
repr = super().to_representation(instance)
repr['products'] = ProductSerializer(instance.products.all(), many=True).data
return repr
def get_fields(self):
fields = super().get_fields()
if self.context['request'].method in ['POST', "PATCH","PUT"]:
fields['products'] = serializers.ListField(
write_only=True,
child=serializers.IntegerField()
)
return fields
将 POST 数据采样到 BundleSerializer
{
"products":[1,2],
"name":"Offer One",
"description":"description",
"price":1212,
"business":1
}