Skip to content

Implementing Custom Validators

Apps can register custom validator classes which implement model validation logic to be executed during a model's clean() method. Like template extensions, custom validators are registered to a single model and offer a method which app authors override to implement their validation logic. This is accomplished by subclassing CustomValidator and implementing the clean() method.

App authors must raise django.core.exceptions.ValidationError within the clean() method to trigger validation error messages which are propagated to the user and prevent saving of the model instance. A convenience method validation_error() may be used to simplify this process. Raising a ValidationError is no different than vanilla Django, and the convenience method will simply pass the provided message through to the exception.

When a CustomValidator is instantiated, the model instance is assigned to context dictionary using the object key, much like TemplateExtension. E.g. self.context['object'].

Declared subclasses should be gathered into a list or tuple for integration with Nautobot. By default, Nautobot looks for an iterable named custom_validators within a custom_validators.py file. (This can be overridden by setting custom_validators to a custom value on the app's NautobotAppConfig.) An example is below.

# custom_validators.py
from nautobot.apps.models import CustomValidator


class LocationValidator(CustomValidator):
    """Custom validator for Locations to enforce that they must have a Tenant."""

    model = 'dcim.location'

    def clean(self):
        if self.context['object'].tenant is None:
            # Enforce that all locations must have a tenant
            self.validation_error({
                "tenant": "All locations must have a tenant"
            })


custom_validators = [LocationValidator]