Введите error для создания и обновления моего списка в 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
Когда я пытаюсь опубликовать некоторые продукты в комплекте продуктов, я получаю "Неверный тип. Ожидаемое значение pk, полученный список".
Читая об этой ошибке, я обнаружил некоторые проблемы, связанные с PrimaryKeyRelatedField и SlugRelatedField. Я знаю, что мне нужно переопределить, но я не знаю, как это сделать.
Это пример того, как опубликовать будет работать:
{
"number": 1,
"bundle": 2,
"product":
[
1,
2
]
}
После просмотра видео, прокомментированного Нилом, я создал следующий метод:
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 в / api / v1 / bundle /
'name' является недопустимым аргументом ключевого слова для этой функции "
3 ответа
Если вы публикуете сообщение через BundleSerializer, вам нужно передать продукты со списком данных ProductSerializer, а не просто id, поскольку продукты в BundleSerializer принимают данные productsSerializer. Вы получаете сообщение об ошибке "имя" является недопустимым аргументом ключевого слова для этой функции " потому что ваши validated_data содержат имя и объект BundleProduct Не имеют поля имени. И вы создаете объекты BundleProduct с validated_data.
Создайте объект пакета и передайте идентификатор объекта пакета объекту BundleProduct.
Если вы не хотите создавать продукт и просто передать существующий идентификатор продукта, вам нужно сделать ListField
Вам нужно переопределить get_fields и проверить запросы
- переопределить to_representation, чтобы всегда возвращать список данных 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
}
Проблема в том, что вы публикуете список BundleProduct
поле продукта пока что ForeignKey
, Присоединиться Bundle
к Product
просто POST
:
{
"bundle": 2,
"product" 1,
"number": 1
}
Вы можете повторить это:
{
"bundle": 2,
"product" 4,
"number": 1
}
добавить еще один продукт 4 к тому же пакету и так далее. Просто убедитесь, что вы делаете их один за другим, а не в списке, как вы делали ранее.
По моему опыту, если вы хотите обновить модель и связанную модель в одном запросе с помощью DRF, самый простой способ сделать это - переопределить метод create для сериализатора. Здесь есть хорошее видео, которое я использовал для справки: https://www.youtube.com/watch?v=EyMFf9O6E60