Просмотр исходного кода

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

Jeremy Stretch 1 год назад
Родитель
Сommit
817e009e4f
2 измененных файлов с 27 добавлено и 6 удалено
  1. 24 3
      netbox/extras/tests/test_customvalidators.py
  2. 3 3
      netbox/extras/validators.py

+ 24 - 3
netbox/extras/tests/test_customvalidation.py → netbox/extras/tests/test_customvalidators.py

@@ -4,7 +4,7 @@ from django.db import transaction
 from django.test import TestCase, override_settings
 
 from dcim.choices import SiteStatusChoices
-from dcim.models import Site
+from dcim.models import Site, Region
 from extras.validators import CustomValidator
 from ipam.models import ASN, RIR
 from users.models import User
@@ -82,6 +82,13 @@ prohibited_validator = CustomValidator({
 })
 
 
+region_validator = CustomValidator({
+    'region.name': {
+        'eq': 'Bar',
+    }
+})
+
+
 request_validator = CustomValidator({
     'request.user.username': {
         'eq': 'Bob'
@@ -154,6 +161,20 @@ class CustomValidatorTest(TestCase):
     def test_valid(self):
         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]})
     def test_custom_invalid(self):
         with self.assertRaises(ValidationError):
@@ -207,7 +228,7 @@ class CustomValidatorConfigTest(TestCase):
     @override_settings(
         CUSTOM_VALIDATORS={
             'dcim.site': (
-                'extras.tests.test_customvalidation.MyValidator',
+                'extras.tests.test_customvalidators.MyValidator',
             )
         }
     )
@@ -254,7 +275,7 @@ class ProtectionRulesConfigTest(TestCase):
     @override_settings(
         PROTECTION_RULES={
             'dcim.site': (
-                'extras.tests.test_customvalidation.MyValidator',
+                'extras.tests.test_customvalidators.MyValidator',
             )
         }
     )

+ 3 - 3
netbox/extras/validators.py

@@ -151,14 +151,14 @@ class CustomValidator:
             return []
 
         # 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(
                 name=name,
                 model=instance.__class__.__name__
             ))
 
-        return getattr(instance, name)
-
     def get_validator(self, descriptor, value):
         """
         Instantiate and return the appropriate validator based on the descriptor given. For