Могу ли я как-то исправить эту ошибку проверки сериализатора?

Я пытаюсь создать заказ в Django с необязательным промокодом, но получаю ошибку валидации:

{
    "promo_code": {
        "code": [
            "This field may not be blank."
        ]
    }
}

Вот мои модели:

class PromoCode(models.Model):
    code = models.CharField(max_length=255, unique=True, db_index=True)

class Order(models.Model):
    promo_code = models.ForeignKey(
        PromoCode, on_delete=models.SET_NULL, null=True, blank=True
    )

В моем OrderSerializer я определяю promo_code, чтобы разрешить null и установить required=False:

from rest_framework import serializers

class PromoCodeSerializer(serializers.ModelSerializer):
    class Meta:
        model = PromoCode
        fields = ['code']

class OrderSerializer(serializers.ModelSerializer):
    promo_code = PromoCodeSerializer(allow_null=True, required=False)

    class Meta:
        model = Order
        fields = ['promo_code']

test_payload = {
            "items": [{"id": "bb6ccdd4-3218-4794-a16a-9327cdfec56f"}],
            "order_date": "2024-11-15",
            "promo_code": {
                "code": ""
            },
            "shipping_info": {
                "shipping_address": "pursitie 7 F"
            },
            "first_name": "Ebenezer",
            "last_name": "Ofori-Mensah",
            "email": "oforimensahebenezer07@gmail.com"
        }

Проблема в том, что при попытке создать заказ без указания промокода (как в test_payload) я все равно получаю ошибку валидации «Это поле не может быть пустым.» для промокода. Я ожидал, что promo_code будет необязательным.

Это пример того, как переопределить def create(self, validated_data) в вашем OrderSerializer классе.

def create(self, validated_data):
    promo_code_data = validated_data.pop('promo_code', None) 
    order = Order.objects.create(**validated_data)
    if promo_code_data:
        promo_code, created = PromoCode.objects.get_or_create(**promo_code_data)
        order.promo_code = promo_code 
        order.save()
        return order

Проблема заключается в том, что вы передаете пустую строку («») для поля кода в словаре promo_code полезной нагрузки. Даже если вы отметили поле поле promo_code как необязательное в вашем OrderSerializer, это не относится к вложенному PromoCodeSerializer. Поле кода в PromoCodeSerializer по-прежнему обязательно и не может быть пустым. В качестве альтернативы можно установить значения allow_blank вместо allow_null=True

class PromoCodeSerializer(serializers.ModelSerializer):
  code = serializers.CharField(allow_blank=True)  

У вас есть и другой вариант, вы можете удалить поле promo_code, сделав какую-нибудь служебную функцию для очистки и затем отправить полезную нагрузку в случае пустого promo_code, если вы не хотите вносить изменения в сериализаторы.

test_payload = {
    "items": [{"id": "bb6ccdd4-3218-4794-a16a-9327cdfec56f"}],
    "order_date": "2024-11-15",
    "shipping_info": {
        "shipping_address": "pursitie 7 F"
    },
    "first_name": "Ebenezer",
    "last_name": "Ofori-Mensah",
    "email": "oforimensahebenezer07@gmail.com"
}

После предложений @sudip-parajuli я изменил свой сериализатор PromoCode следующим образом:

class PromoCodeSerializer(serializers.ModelSerializer):
    code = serializers.CharField(allow_blank=True)
    class Meta:
        model = PromoCode

Я также переопределил метод validate в OrderSerializer, чтобы удалить данные promo_code, когда значение кода пустое:

def validate(self, data: dict):
    promo_code_data: dict = data.get("promo_code", None)
    if promo_code_data and promo_code_data.get("code"):
        return data
    else:
        data.pop("promo_code", None)
        return data

Решил мою проблему.

Нет смысла передавать пустую строку в качестве code, чтобы использовать ее в качестве None для promo_code.

Если промо-код отсутствует, вы передаете его как null:

{
  "items": [
    {
      "id": "bb6ccdd4-3218-4794-a16a-9327cdfec56f"
    }
  ],
  "order_date": "2024-11-15",
  "promo_code": null,
  "shipping_info": {
    "shipping_address": "pursitie 7 F"
  },
  "first_name": "Ebenezer",
  "last_name": "Ofori-Mensah",
  "email": "oforimensahebenezer07@gmail.com"
}

или не указывать его вовсе:

{
  "items": [
    {
      "id": "bb6ccdd4-3218-4794-a16a-9327cdfec56f"
    }
  ],
  "order_date": "2024-11-15",
  "shipping_info": {
    "shipping_address": "pursitie 7 F"
  },
  "first_name": "Ebenezer",
  "last_name": "Ofori-Mensah",
  "email": "oforimensahebenezer07@gmail.com"
}

Если вы указываете promo_code, то это означает, что существует связанный с ним объект PromoCode. Рассматривая это как некое «не значение», вы создаете несколько представлений для null, что, как правило, только усложняет задачу.

Вернуться на верх