Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make cerberus required rule depends on condition

I have a big json document, where some fields should be required if other fields have exact values. E.g.

document = {'is_realty_address': False, 'postcode': 111111}

postcode have to be required if is_realty_address == False. All of the rules (except 'required') are applied to the fields that are exist in document, so my custom rules are silent, when I have

document = {'is_realty_address': False}

of-rules won't help in my case, because I have plenty of "conditional-required" fields which depends on many different fields. So, of-rules will strongly complicate my schema. Dependencies don't work too. I tried:

{'postcode': {'dependencies': {'is_realty_address': False}, 'required': True}}

This returns error if postcode not appears in document, no matter what value has is_realty_address

v = Validator()
print(v.validate({'is_realty_address': False}, schema))
print(v.errors)

print(v.validate({'is_realty_address': True}, schema))
print(v.errors)

this code returns:

False
{'postcode': ['required field']}
False
{'postcode': ['required field']}

I also tried to implement validation method:

def _validate_conditional_required(self, conditional_required, field, value):
    """
    :param conditional_required:
    :param field:
    :param value:
    :return:
    The rule's arguments are validated against this schema:
    {'type': 'dict'}
    """
    for conditional_field, conditional_value in conditional_required.items():
        if self.document[conditional_field] == conditional_value and field not in self.document:
            self._error(field, errors.REQUIRED_FIELD)

with schema

schema = {
    'is_realty_address': {'required': True, 'type': 'boolean'},
    'postcode': {'conditional_required': {'is_realty_address': False}},
}

but this rule doesn't run if 'postcode' is not in the document.

Is there any way to set "conditional-required" rule? I want to see this code:

schema = {
    'is_realty_address': {'required': True, 'type': 'boolean'},
    'postcode': {'conditional_required': {'is_realty_address': False}},
}
v = Validator()
print(v.validate({'is_realty_address': False}, schema))
print(v.errors)

print(v.validate({'is_realty_address': True}, schema))
print(v.errors)

returns:

True

False
{'postcode': ['required field']}
like image 761
Dmitry Bozhenko Avatar asked Feb 14 '18 14:02

Dmitry Bozhenko


1 Answers

I figured out, that my issue can be solved with combination of 'excludes' and 'oneof' rule

schema = {
'is_realty_address': {
    'required': True, 'type': 'boolean',
    'oneof': [{'excludes': 'postcode', 'allowed': [False]}, {'allowed': [True]}]
},
'postcode': {'type': 'integer', 'required': True}}
v = Validator()
print(v.validate({'is_realty_address': True}, schema))
print(v.errors)

print(v.validate({'is_realty_address': False, 'postcode': 111111}, schema))
print(v.errors)

This code returns:

False
{'postcode': ['required field']}
False
{'is_realty_address': [{'oneof': ['none or more than one rule validate', {'oneof definition 1': ['unallowed value False'], 'oneof definition 0': ["'postcode' must not be present with 'is_realty_address'"]}]}]}

So, schema won't be strongly complicated with this variant.

like image 129
Dmitry Bozhenko Avatar answered Oct 20 '22 16:10

Dmitry Bozhenko