Могу ли я как-то исправить эту ошибку проверки сериализатора?
Я пытаюсь создать заказ в 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, что, как правило, только усложняет задачу.