1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Closes #15490: CustomValidator support for accessing related object attribute via dotted path

This commit is contained in:
Jeremy Stretch
2024-03-22 15:34:07 -04:00
parent 74444da7b8
commit 817e009e4f
2 changed files with 27 additions and 6 deletions

View File

@ -4,7 +4,7 @@ from django.db import transaction
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from dcim.choices import SiteStatusChoices from dcim.choices import SiteStatusChoices
from dcim.models import Site from dcim.models import Site, Region
from extras.validators import CustomValidator from extras.validators import CustomValidator
from ipam.models import ASN, RIR from ipam.models import ASN, RIR
from users.models import User from users.models import User
@ -82,6 +82,13 @@ prohibited_validator = CustomValidator({
}) })
region_validator = CustomValidator({
'region.name': {
'eq': 'Bar',
}
})
request_validator = CustomValidator({ request_validator = CustomValidator({
'request.user.username': { 'request.user.username': {
'eq': 'Bob' 'eq': 'Bob'
@ -154,6 +161,20 @@ class CustomValidatorTest(TestCase):
def test_valid(self): def test_valid(self):
Site(name='abcdef123', slug='abcdef123').clean() Site(name='abcdef123', slug='abcdef123').clean()
@override_settings(CUSTOM_VALIDATORS={'dcim.site': [region_validator]})
def test_valid(self):
region1 = Region(name='Foo', slug='foo')
region1.save()
region2 = Region(name='Bar', slug='bar')
region2.save()
# Invalid region
with self.assertRaises(ValidationError):
Site(name='abcdef123', slug='abcdef123', region=region1).clean()
# Valid region
Site(name='abcdef123', slug='abcdef123', region=region2).clean()
@override_settings(CUSTOM_VALIDATORS={'dcim.site': [custom_validator]}) @override_settings(CUSTOM_VALIDATORS={'dcim.site': [custom_validator]})
def test_custom_invalid(self): def test_custom_invalid(self):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
@ -207,7 +228,7 @@ class CustomValidatorConfigTest(TestCase):
@override_settings( @override_settings(
CUSTOM_VALIDATORS={ CUSTOM_VALIDATORS={
'dcim.site': ( 'dcim.site': (
'extras.tests.test_customvalidation.MyValidator', 'extras.tests.test_customvalidators.MyValidator',
) )
} }
) )
@ -254,7 +275,7 @@ class ProtectionRulesConfigTest(TestCase):
@override_settings( @override_settings(
PROTECTION_RULES={ PROTECTION_RULES={
'dcim.site': ( 'dcim.site': (
'extras.tests.test_customvalidation.MyValidator', 'extras.tests.test_customvalidators.MyValidator',
) )
} }
) )

View File

@ -151,14 +151,14 @@ class CustomValidator:
return [] return []
# Raise a ValidationError for unknown attributes # Raise a ValidationError for unknown attributes
if not hasattr(instance, name): try:
return operator.attrgetter(name)(instance)
except AttributeError:
raise ValidationError(_('Invalid attribute "{name}" for {model}').format( raise ValidationError(_('Invalid attribute "{name}" for {model}').format(
name=name, name=name,
model=instance.__class__.__name__ model=instance.__class__.__name__
)) ))
return getattr(instance, name)
def get_validator(self, descriptor, value): def get_validator(self, descriptor, value):
""" """
Instantiate and return the appropriate validator based on the descriptor given. For Instantiate and return the appropriate validator based on the descriptor given. For