[Fixed]-Django model validation, pass current value to function?

1👍

When you’re doing validators=[validate_dmvpn_ip('','172.16.100.')], you end up with the return value of calling the validation function as the validator (which is validators=[None] because you’re not returning anything). It looks like you’re trying to create a customizable validation function. For that you’ll need to write a function that returns a another:

def validate_dmvpn_ip(subnet):
    from django.core.exceptions import ValidationError

    def validator(value):
        if subnet not in value or value != '0.0.0.0':
            raise ValidationError('Invalid IP address, please check corrent octects have been assigned')

    return validator

And you use it like so:

# outside model:
main_validator = validate_dmvpn_ip('172.16.100.')
main_validator.__name__ = 'main_validator'
main_validator.__module__ = 'path.to.this.module'

# inside model
dmvpn_dsl = models.GenericIPAddressField(protocol='IPv4', verbose_name="DMVPN DSL IP", \
    validators=[main_validator], blank=True, null=True)

The outer function returns another function that takes a value to validate, but still has access to the subnet to validate against.

Notice how I’m signing the validator to another variable and assigning the __name__ and __module__ attributes. While this is normally not needed, django needs to be able to refer to the validator directly for migration purposes, and a returned function is not assigned anywhere. Of course if you only have one such validator, you can hardcode the subnet and avoid this mess:

def validate_dmvpn_ip(value):
    subnet = '172.16.100.'
    from django.core.exceptions import ValidationError

    if subnet not in value or value != '0.0.0.0':
        raise ValidationError('Invalid IP address, please check corrent octects have been assigned')

and

dmvpn_dsl = models.GenericIPAddressField(protocol='IPv4', verbose_name="DMVPN DSL IP", \
    validators=[validate_dmvpn_ip], blank=True, null=True)

To learn more about nested functions (closures), take a look at decorators in python which are basically this + special @ syntax.

Leave a comment