Pytest. AssertionError при отправке POST-запроса в тестах DjangoRestFramework

Есть модель заказа:

class Order(models.Model):
    """ Модель заказов """

    user = models.ForeignKey(
        User,
        verbose_name="Пользователь",
        on_delete=models.CASCADE,
        related_name="order"
    )
    status = models.TextField(
        OrderStatusChoices.choices,
        default=OrderStatusChoices.NEW
    )
    products = models.ManyToManyField(Product, related_name='order', through='Position')
    count = models.PositiveIntegerField(editable=False)
    total = models.FloatField(editable=False)
    created_at = models.DateTimeField("Создано", auto_now_add=True)
    updated_at = models.DateTimeField("Обновлено", auto_now=True)

    def __str__(self):
        return "User: {} has {} items in order. Their total is ${}".format(self.user, self.count, self.total)

    class Meta:
        verbose_name = "Заказ"
        verbose_name_plural = "Заказы"
        ordering = ["created_at"]

промежуточная таблица Position для связи Order и Product:

class Position(models.Model):
    """ Позиции товаров """

    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='position')
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='position')
    quantity = models.PositiveIntegerField()

    def __str__(self):
        return "This entry contains {} {}(s).".format(self.quantity, self.product.name)

    class Meta:
        verbose_name = "Наименование"
        verbose_name_plural = "Наименования"

Сериализаторы:

class OrderSerializer(serializers.ModelSerializer):
    """ Сериализатор списка заказов """

    user = serializers.SlugRelatedField(
        slug_field='username',
        read_only=True,
    )

    products = PositionSerializer(many=True, source='position.all')

    class Meta:
        model = Order
        fields = '__all__'
        read_only_fields = ('status',)

    def create(self, validated_data):
        validated_data['user'] = self.context["request"].user
        positions = validated_data.pop(
            'position')
        positions_objs = []
        validated_data['count'] = 0
        validated_data['total'] = 0
        order = super().create(validated_data)
        for position in positions.values():
            for item in position:
                price = Product.objects.get(id=item['product'].id).price
                validated_data['total'] += price * item['quantity']
                validated_data['count'] += item['quantity']
                positions_objs.append(Position(quantity=item['quantity'], product=item['product'], order=order))
        order.count = validated_data['count']
        order.total = validated_data['total']
        order.save()
        Position.objects.bulk_create(positions_objs)
        return order


class OrderDetailSerializer(serializers.ModelSerializer):
    """ Сериализатор конкретного заказа """

    user = serializers.SlugRelatedField(
        slug_field='username',
        read_only=True,
    )

    position = PositionSerializer(many=True, read_only=True)

    class Meta:
        model = Order
        fields = ('user', 'status', 'total', 'count', 'position', 'created_at', 'updated_at')

    def update(self, instance, validated_data):
        """Метод для обновления + проверка на допустимость изменения"""
        if self.context['request'].user.is_authenticated:
            if validated_data['status'] == 'CANCELLED':
                instance.status = validated_data.get('status', instance.status)
                instance.updated_at = datetime.now()
                instance.save()
                return instance
            else:
                raise ValidationError({"Order": "Авторизованный пользователь может менять статус только на 'Отменён'"})
        elif self.context['request'].user.is_staff or self.context['request'].user.is_superuser:
            instance.status = validated_data.get('status', instance.status)
            instance.updated_at = datetime.now()
            instance.save()
            return instance
        else:
            raise ValidationError({"Order": "Менять статус заказа может только админ"})

Всё прекрасно работает. Через Api DRF всё работает - запросы на создание заказа отправляются и сохраняются в БД. Также использую Talend Api Tester. В нём тоже всё прекрасно. Но в тестах происходит ошибка. Тест создания:

@pytest.mark.django_db
def test_create_order_and_positions_by_authenticated_client(product_factory, authenticated_client):
    """ Тест на создание заказа и позиций заказа  """
    product_factory(_quantity=3)
    url = reverse("orders-list")
    order = {'products': [{
                "product": 1,
                "quantity": 1
            },
            {
                "product": 2,
                "quantity": 2
            },
            {
                "product": 3,
                "quantity": 5
            }]}
    resp = authenticated_client.post(url, order, format='json')
    print(resp.json())
    assert resp.status_code == HTTP_201_CREATED

Print выдаёт следующую информацию:

FAILED [100%]{'products': ['Обязательное поле.']}

Файл settings проекта:

REST_FRAMEWORK = {
    'TEST_REQUEST_DEFAULT_FORMAT': 'json'
    }

Если убрать из настроек формат по умолчанию, либо не передавать с запросом, то ничего не меняется - та же ошибка. Не могу понять, что не так. Если надо что-то добавить - пишите


Ответы (1 шт):

Автор решения: Andrey Belyanin

Нашёл ответ:

@pytest.mark.django_db
def test_create_order_and_positions_by_authenticated_client(product_factory, authenticated_client):
    """ Тест на создание заказа и позиций заказа  """
    product_factory(_quantity=3)
    url = reverse("orders-list")
    order = {'products': [{
                "product": 1,
                "quantity": 1
            },
            {
                "product": 2,
                "quantity": 2
            },
            {
                "product": 3,
                "quantity": 5
            }]}
    resp = authenticated_client.post(url, order, content_type='application/json')
    print(resp.json())
    assert resp.status_code == HTTP_201_CREATED

нужно было вместо format='json' указать content_type='application/json'. Я сперва написал тест с указанием формата в настройках, как это сказано в документации - не сработало и я полез в интернет. Мне ответили, что нужно, либо в настройках указать по умолчанию формат(как у меня сделано было), либо дописать format='json'. Я сделал и это не помогло, поэтому написал здесь, но пока ждал ответа нашёл ответ сам.

→ Ссылка