Is there any way I can fix this serializer validation error?
I'm trying to create an Order in Django with an optional promo_code, but I'm getting a validation error:
{
"promo_code": {
"code": [
"This field may not be blank."
]
}
}
Here are my models:
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
)
In my OrderSerializer, I define promo_code to allow null and set 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"
}
The issue is that when trying to create an order without providing a promo_code (like test_payload), I still get the validation error saying "This field may not be blank." for promo_code. I expected promo_code to be optional.
Thi is an example of how to override the def create(self, validated_data)
under your OrderSerializer
class.
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
The issue is since you're passing an empty string ("") for the code field in the promo_code dictionary of the payload. Even though you've marked the promo_code field as optional in your OrderSerializer, this does not apply to the nested PromoCodeSerializer. The code field in PromoCodeSerializer is still required and cannot be blank. Alternatively what you can do is you can set allow_blank values instead of allow_null=True
class PromoCodeSerializer(serializers.ModelSerializer):
code = serializers.CharField(allow_blank=True)
You have another option too you can remove the promo_code field by making some utility function to clean things and then send the payload incase of empty promo_code, if you don't want to make change to the serializers.
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"
}
Following @sudip-parajuli's suggestions I modified my PromoCode serializer as below:
class PromoCodeSerializer(serializers.ModelSerializer):
code = serializers.CharField(allow_blank=True)
class Meta:
model = PromoCode
I also overrode the validate method of the OrderSerializer to remove promo_code data when the code value is empty:
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
Solved my problem.