Введите error для создания и обновления моего списка в django rest framework - PullRequest
0 голосов
/ 25 февраля 2019

Я пытаюсь использовать мой 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__"

Но не работает.Я получаю эту ошибку: "Ошибка типа в / api / v1 / bundle /

'name' является недопустимым аргументом ключевого слова для этой функции"

Ответы [ 3 ]

0 голосов
/ 25 февраля 2019

Проблема здесь в том, что вы публикуете список в поле продукта BundleProduct, но это ForeignKey.Чтобы присоединить Bundle к Product, просто POST:

{
  "bundle": 2,
  "product" 1,
  "number": 1
}

Вы можете повторить это:

{
  "bundle": 2,
  "product" 4,
  "number": 1
}

, чтобы добавить еще один продукт 4 в тот же пакет искоро.Просто убедитесь, что вы делаете их один за другим, а не в списке, как вы делали ранее.

0 голосов
/ 26 февраля 2019

Если вы публикуете сообщение через BundleSerializer, вам нужно передать продукты со списком данных ProductSerializer, а не просто id, поскольку продукты в BundleSerializer принимают данные productsSerializer.Вы получаете ошибка типа 'имя' является недопустимым аргументом ключевого слова для этой функции ", поскольку ваши validated_data содержат имя и объект BundleProduct Не имеют поля имени. И вы создаете объекты BundleProduct с validated_data.

Создание объекта пакета и передача идентификатора объекта пакета в объект BundleProduct.

  • Если вы не хотите создавать продукт и просто передаете существующий идентификатор продукта, необходимо сделать ListField

  • Вам необходимо переопределить get_fields и проверить запросы

  • переопределить to_representation , чтобы всегда возвращать список данных ProdutSerializer
  • Переопределить Создать для POST Запрос
  • Переопределить Обновление для PUT и PATCH Запрос

Ниже приведено решение для POST Запрос

Для PATCH И 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

}
0 голосов
/ 25 февраля 2019

По моему опыту, если вы хотите обновить модель и связанную модель за один запрос с помощью DRF, самый простой способ сделать это - переопределить метод create сериализатора.Здесь есть хорошее видео, которое я использовал для справки: https://www.youtube.com/watch?v=EyMFf9O6E60

...