diff --git a/docs/reference/conditions.md b/docs/reference/conditions.md index c335bf9a8..40b2ccb4b 100644 --- a/docs/reference/conditions.md +++ b/docs/reference/conditions.md @@ -23,14 +23,47 @@ A condition is expressed as a JSON object with the following keys: * `in`: Is present within a list of values * `contains`: Contains the specified value +### Accessing Nested Keys + +To access nested keys, use dots to denote the path to the desired attribute. For example, assume the following data: + +```json +{ + "a": { + "b": { + "c": 123 + } + } +} +``` + +The following condition will evaluate as true: + +```json +{ + "attr": "a.b.c", + "value": 123 +} +``` + ### Examples -`name` equals "foobar": +`name` equals "foo": ```json { "attr": "name", - "value": "foobar" + "value": "foo" +} +``` + +`name` does not equal "foo" + +```json +{ + "attr": "name", + "value": "foo", + "negate": true } ``` diff --git a/netbox/extras/conditions.py b/netbox/extras/conditions.py index 6f1b012eb..965488c3a 100644 --- a/netbox/extras/conditions.py +++ b/netbox/extras/conditions.py @@ -64,7 +64,11 @@ class Condition: """ Evaluate the provided data to determine whether it matches the condition. """ - value = functools.reduce(dict.get, self.attr.split('.'), data) + try: + value = functools.reduce(dict.get, self.attr.split('.'), data) + except TypeError: + # Invalid key path + value = None result = self.eval_func(value) if self.negate: diff --git a/netbox/extras/tests/test_conditions.py b/netbox/extras/tests/test_conditions.py index ee6afeaf6..8e02eb75d 100644 --- a/netbox/extras/tests/test_conditions.py +++ b/netbox/extras/tests/test_conditions.py @@ -35,6 +35,16 @@ class ConditionTestCase(TestCase): # 'gt' supports only numeric values Condition('x', 'foo', 'gt') + # + # Nested attrs tests + # + + def test_nested(self): + c = Condition('x.y.z', 1) + self.assertTrue(c.eval({'x': {'y': {'z': 1}}})) + self.assertFalse(c.eval({'x': {'y': {'z': 2}}})) + self.assertFalse(c.eval({'a': {'b': {'c': 1}}})) + # # Operator tests #