Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework - conditionally make serializer's field required or not using other field value

In my DRF project, I have a model:

class Item(BaseModel):
    PRIVATE = 'PRIVATE'
    COMPANY = 'COMPANY'
    ACCOUNT_TYPES = (
        (PRIVATE, _('Private')),
        (COMPANY, _('Company')),
    )
    company_name = models.CharField(max_length=128, null=True, blank=True)
    person_name = models.CharField(max_length=128, null=True, blank=True)
    account_type = models.CharField(max_length=32, choices=ACCOUNT_TYPES)
    phone = models.CharField(max_length=128, null=True, blank=True)
    email = models.EmailField(max_length=128, null=True, blank=True)

and ItemSerializer in serializers like:

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ('account_type', 'company_name', 'person_name')

    def create(self, validated_data):
        print('ItemSerializer, create')
        print('validated_data:', validated_data)
        return super().create(validated_data)

    def validate(self, attrs):
        print('ItemSerializer validate, attrs:', attrs)
        return attrs

as you can see in the model, there are fields company_name and person_name, none of them is required in the model.

To create an Item, account_type has to be specified. Its either PRIVATE or COMPANY.

Now, in my serializer I want to make specific fields required if account type is company or private. For example, is account_type is COMPANY, I want to make field company_name required. If account_type is PRIVATE I want to make person_name required.

  1. Which method is a proper space to achieve this and how can I do this?
  2. Also using above logic I want to do extra validation on the field. Example: is account_type is PRIVATE and person_name is not empty, I want to do some validation on person_name (check if it has a proper format, length etc)
like image 621
dease Avatar asked Oct 20 '25 15:10

dease


2 Answers

You can use def validate(self, data) to check condition required, and def validate_{field_name}(self, value) for extra validation:

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ('account_type', 'company_name', 'person_name')
        extra_kwargs = {
            'company_name': {'required': False},
            'person_name': {'required': False},
        }

    def validate(self, data):
        data_dict = dict(data)
        data_keys = data.keys()
        account_type= data_dict.get('account_type')
        if account_type == 'PRIVATE' and 'person_name' not in data_keys:
            raise serializers.ValidationError('person_name required when account_type is PRIVATE.')
        if account_type == 'COMPANY' and 'company_name' not in data_keys:
            raise serializers.ValidationError('company_name required when account_type is COMPANY.')
        return data

    def validate_person_name(self, value):
        if len(value) < 10:
            raise serializers.ValidationError('person_name must be at least 10 characters.')
        return value
like image 98
Kasra Najafi Avatar answered Oct 23 '25 04:10

Kasra Najafi


You can use the validate method of the serializer that receives all the serialized fields as parameter, see here.

like image 25
piedra Avatar answered Oct 23 '25 04:10

piedra



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!