Search code examples
pythoncerberus

How can I validate a field depending on the lenght of another field with Cerberus?


Is there a way to validate document where existence of one field depends of length of other field? My try:

import cerberus

schema = {
    'field_2': {
        'type': 'integer',
        'dependencies': {
            'field_1': {'maxlength': 1}
        }
    },
    'field_1': {
        'type': 'list',
    }
}
v = cerberus.Validator(schema)
doc = {
    'field_1': [1, ],
    'field_2': 77
}
if not v.validate(doc):
    print(v.errors)
else:
    print(True)

output:

{'field_2': ["depends on these values: {'field_1': {'maxlength': 1}}"]}

expected output is True


Solution

  • it can be done using custom rules:

    from typing import Optional, Any, Tuple
    
    from cerberus import Validator
    
    
    class ExtendedValidator(Validator):
        def _validate_with_length(self, with_length, field, _value):
            # type: (Tuple[str, int], str, Any) -> Optional[bool]
            """Validating in dependence of length of other field in document
    
            The rule's arguments are validated against this schema:
            {'type': 'list'}
            """
            key, length = with_length
            if key not in self.document:
                return False
            if len(self.document[key]) != length:
                self._error(field, "Length of %s must be %s" % (key, length))
    
    
    schema = {
        'field_2': {
            'type': 'integer',
            'with_length': ('field_1', 1),
        },
        'field_1': {
            'type': 'list',
        }
    }
    
    docs = [{'field_1': [1, ], 'field_2': 77}, {'field_1': [1, 2], 'field_2': 77}]
    v = ExtendedValidator(schema)
    for doc in docs:
        if not v.validate(doc):
            print(v.errors)
        else:
            print(True)
    

    output:

    True
    {'field_2': ['Length of field_1 must be 1']}