简体   繁体   中英

Django rest framework conditionally required fields

I would like to write a drf validator that will mark a field as required based on the value of an other field. For example:

class MySerializer(serializers.Serializer):
    has_children = fields.BooleanField()
    nb_childs = fields.IntegerField(min_value=1, validators=[RequiredIf(field='has_children', value=True)], required=False)

At first i believed the class based validator was the way to do it, by retrieving the value of 'has_children' with a method like this:

def set_context(self, serializer_field):
    print serializer_field.parent.initial_data

but the 'initial_data' is not set. Any clue?

Have a look here in the DRF documentation

Basically, to do object-level validation, you need to override the Serializer's validate(self, data) method, do your validation using the data parameter's value (this is the serializer's state provided as a dict to validate) then raise a ValidationError if anything is wrong.

If you need to raise an error for a specific field, then you can pass a dictionary as the parameter to the ValidationError constructor:

raise ValidationError({'yourfield': ['Your message']})

I am using several mixins for that purpose, which are changing field . required attribute and as result error validation messages are generated automatically by DRF

PerFieldMixin

class ConditionalRequiredPerFieldMixin:
"""Allows to use serializer methods to allow change field is required or not"""

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for field_name, field in self.fields.items():
        method_name = f'is_{field_name}_required'
        if hasattr(self, method_name):
            field.required = getattr(self, method_name)()

How to use PerFieldMixin

class MySerializer(ConditionalRequiredPerFieldMixin, serializers.ModelSerializer):
    subject_id = serializers.CharField(max_length=128, min_length=3, required=False)

    def is_subject_id_required(self):
        study = self.context['study']
        return not study.is_community_study

PerActionMixin

class ActionRequiredFieldsMixin:
    """Required fields per DRF action
    Example:
    PER_ACTION_REQUIRED_FIELDS = {
        'update': ['notes']
    }
    """
    PER_ACTION_REQUIRED_FIELDS = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.context.get('view'):
            action = self.context['view'].action
            required_fields = (self.PER_ACTION_REQUIRED_FIELDS or {}).get(action)
            if required_fields:
                for field_name in required_fields:
                    self.fields[field_name].required = True

How to use PerActionMixin

see docstrings, for action == update (ie PUT request) - field "notes" will be required)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM