mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Closes #2495: Enable deep-merging of config context data
This commit is contained in:
@ -3,6 +3,7 @@ v2.4.9 (FUTURE)
|
||||
## Enhancements
|
||||
|
||||
* [#2089](https://github.com/digitalocean/netbox/issues/2089) - Add SONET interface form factors
|
||||
* [#2495](https://github.com/digitalocean/netbox/issues/2495) - Enable deep-merging of config context data
|
||||
* [#2597](https://github.com/digitalocean/netbox/issues/2597) - Add FibreChannel SFP28 (32GFC) interface form factor
|
||||
|
||||
## Bug Fixes
|
||||
|
@ -18,7 +18,7 @@ from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from dcim.constants import CONNECTION_STATUS_CONNECTED
|
||||
from utilities.utils import foreground_color
|
||||
from utilities.utils import deepmerge, foreground_color
|
||||
from .constants import *
|
||||
from .querysets import ConfigContextQuerySet
|
||||
|
||||
@ -727,11 +727,11 @@ class ConfigContextModel(models.Model):
|
||||
# Compile all config data, overwriting lower-weight values with higher-weight values where a collision occurs
|
||||
data = OrderedDict()
|
||||
for context in ConfigContext.objects.get_for_object(self):
|
||||
data.update(context.data)
|
||||
data = deepmerge(data, context.data)
|
||||
|
||||
# If the object has local config context data defined, that data overwrites all rendered data
|
||||
# If the object has local config context data defined, merge it last
|
||||
if self.local_context_data is not None:
|
||||
data.update(self.local_context_data)
|
||||
data = deepmerge(data, self.local_context_data)
|
||||
|
||||
return data
|
||||
|
||||
|
89
netbox/utilities/tests/test_utils.py
Normal file
89
netbox/utilities/tests/test_utils.py
Normal file
@ -0,0 +1,89 @@
|
||||
from django.test import TestCase
|
||||
|
||||
from utilities.utils import deepmerge
|
||||
|
||||
|
||||
class DeepMergeTest(TestCase):
|
||||
"""
|
||||
Validate the behavior of the deepmerge() utility.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
return
|
||||
|
||||
def test_deepmerge(self):
|
||||
|
||||
dict1 = {
|
||||
'active': True,
|
||||
'foo': 123,
|
||||
'fruits': {
|
||||
'orange': 1,
|
||||
'apple': 2,
|
||||
'pear': 3,
|
||||
},
|
||||
'vegetables': None,
|
||||
'dairy': {
|
||||
'milk': 1,
|
||||
'cheese': 2,
|
||||
},
|
||||
'deepnesting': {
|
||||
'foo': {
|
||||
'a': 10,
|
||||
'b': 20,
|
||||
'c': 30,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dict2 = {
|
||||
'active': False,
|
||||
'bar': 456,
|
||||
'fruits': {
|
||||
'banana': 4,
|
||||
'grape': 5,
|
||||
},
|
||||
'vegetables': {
|
||||
'celery': 1,
|
||||
'carrots': 2,
|
||||
'corn': 3,
|
||||
},
|
||||
'dairy': None,
|
||||
'deepnesting': {
|
||||
'foo': {
|
||||
'a': 100,
|
||||
'd': 40,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
merged = {
|
||||
'active': False,
|
||||
'foo': 123,
|
||||
'bar': 456,
|
||||
'fruits': {
|
||||
'orange': 1,
|
||||
'apple': 2,
|
||||
'pear': 3,
|
||||
'banana': 4,
|
||||
'grape': 5,
|
||||
},
|
||||
'vegetables': {
|
||||
'celery': 1,
|
||||
'carrots': 2,
|
||||
'corn': 3,
|
||||
},
|
||||
'dairy': None,
|
||||
'deepnesting': {
|
||||
'foo': {
|
||||
'a': 100,
|
||||
'b': 20,
|
||||
'c': 30,
|
||||
'd': 40,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
self.assertEqual(
|
||||
deepmerge(dict1, dict2),
|
||||
merged
|
||||
)
|
@ -1,5 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from collections import OrderedDict
|
||||
import datetime
|
||||
import json
|
||||
import six
|
||||
@ -109,3 +110,16 @@ def serialize_object(obj, extra=None):
|
||||
data.update(extra)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def deepmerge(original, new):
|
||||
"""
|
||||
Deep merge two dictionaries (new into original) and return a new dict
|
||||
"""
|
||||
merged = OrderedDict(original)
|
||||
for key, val in new.items():
|
||||
if key in original and isinstance(original[key], dict) and isinstance(val, dict):
|
||||
merged[key] = deepmerge(original[key], val)
|
||||
else:
|
||||
merged[key] = val
|
||||
return merged
|
||||
|
Reference in New Issue
Block a user