mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 01:41:22 -06:00
* Employ native PostgreSQL functions for updating object JSON data when adding/removing custom fields * Optimize rename_object_data() * remove_stale_data() should validate model class
This commit is contained in:
parent
8ab73501d1
commit
af5a600583
@ -9,6 +9,8 @@ from django.conf import settings
|
|||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
from django.core.validators import RegexValidator, ValidationError
|
from django.core.validators import RegexValidator, ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import F, Func, Value
|
||||||
|
from django.db.models.expressions import RawSQL
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
@ -281,12 +283,20 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
|
|||||||
Populate initial custom field data upon either a) the creation of a new CustomField, or
|
Populate initial custom field data upon either a) the creation of a new CustomField, or
|
||||||
b) the assignment of an existing CustomField to new object types.
|
b) the assignment of an existing CustomField to new object types.
|
||||||
"""
|
"""
|
||||||
|
if self.default is None:
|
||||||
|
# We have to convert None to a JSON null for jsonb_set()
|
||||||
|
value = RawSQL("'null'::jsonb", [])
|
||||||
|
else:
|
||||||
|
value = Value(self.default, models.JSONField())
|
||||||
for ct in content_types:
|
for ct in content_types:
|
||||||
model = ct.model_class()
|
ct.model_class().objects.update(
|
||||||
instances = model.objects.exclude(**{'custom_field_data__contains': self.name})
|
custom_field_data=Func(
|
||||||
for instance in instances:
|
F('custom_field_data'),
|
||||||
instance.custom_field_data[self.name] = self.default
|
Value([self.name]),
|
||||||
model.objects.bulk_update(instances, ['custom_field_data'], batch_size=100)
|
value,
|
||||||
|
function='jsonb_set'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def remove_stale_data(self, content_types):
|
def remove_stale_data(self, content_types):
|
||||||
"""
|
"""
|
||||||
@ -295,22 +305,27 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
|
|||||||
"""
|
"""
|
||||||
for ct in content_types:
|
for ct in content_types:
|
||||||
if model := ct.model_class():
|
if model := ct.model_class():
|
||||||
instances = model.objects.filter(custom_field_data__has_key=self.name)
|
model.objects.update(
|
||||||
for instance in instances:
|
custom_field_data=F('custom_field_data') - self.name
|
||||||
del instance.custom_field_data[self.name]
|
)
|
||||||
model.objects.bulk_update(instances, ['custom_field_data'], batch_size=100)
|
|
||||||
|
|
||||||
def rename_object_data(self, old_name, new_name):
|
def rename_object_data(self, old_name, new_name):
|
||||||
"""
|
"""
|
||||||
Called when a CustomField has been renamed. Updates all assigned object data.
|
Called when a CustomField has been renamed. Removes the original key and inserts the new
|
||||||
|
one, copying the value of the old key.
|
||||||
"""
|
"""
|
||||||
for ct in self.object_types.all():
|
for ct in self.object_types.all():
|
||||||
model = ct.model_class()
|
ct.model_class().objects.update(
|
||||||
params = {f'custom_field_data__{old_name}__isnull': False}
|
custom_field_data=Func(
|
||||||
instances = model.objects.filter(**params)
|
F('custom_field_data') - old_name,
|
||||||
for instance in instances:
|
Value([new_name]),
|
||||||
instance.custom_field_data[new_name] = instance.custom_field_data.pop(old_name)
|
Func(
|
||||||
model.objects.bulk_update(instances, ['custom_field_data'], batch_size=100)
|
F('custom_field_data'),
|
||||||
|
function='jsonb_extract_path_text',
|
||||||
|
template=f"to_jsonb(%(expressions)s -> '{old_name}')"
|
||||||
|
),
|
||||||
|
function='jsonb_set')
|
||||||
|
)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super().clean()
|
super().clean()
|
||||||
|
Loading…
Reference in New Issue
Block a user