Przeglądaj źródła

Clean up stale data when a custom field is changed/deleted

Jeremy Stretch 5 lat temu
rodzic
commit
2d56a658b3
2 zmienionych plików z 37 dodań i 1 usunięć
  1. 11 0
      netbox/extras/models/customfields.py
  2. 26 1
      netbox/extras/signals.py

+ 11 - 0
netbox/extras/models/customfields.py

@@ -116,6 +116,17 @@ class CustomField(models.Model):
     def __str__(self):
         return self.label or self.name.replace('_', ' ').capitalize()
 
+    def remove_stale_data(self, content_types):
+        """
+        Delete custom field data which is no longer relevant (either because the CustomField is
+        no longer assigned to a model, or because it has been deleted).
+        """
+        for ct in content_types:
+            model = ct.model_class()
+            for obj in model.objects.filter(**{f'custom_field_data__{self.name}__isnull': False}):
+                del(obj.custom_field_data[self.name])
+                obj.save()
+
     def clean(self):
         # Choices can be set only on selection fields
         if self.choices and self.type != CustomFieldTypeChoices.TYPE_SELECT:

+ 26 - 1
netbox/extras/signals.py

@@ -3,12 +3,14 @@ from datetime import timedelta
 
 from cacheops.signals import cache_invalidated, cache_read
 from django.conf import settings
+from django.contrib.contenttypes.models import ContentType
+from django.db.models.signals import m2m_changed, pre_delete
 from django.utils import timezone
 from django_prometheus.models import model_deletes, model_inserts, model_updates
 from prometheus_client import Counter
 
 from .choices import ObjectChangeActionChoices
-from .models import ObjectChange
+from .models import CustomField, ObjectChange
 from .webhooks import enqueue_webhooks
 
 
@@ -71,6 +73,29 @@ def _handle_deleted_object(request, sender, instance, **kwargs):
     model_deletes.labels(instance._meta.model_name).inc()
 
 
+#
+# Custom fields
+#
+
+def handle_cf_removed_obj_types(instance, action, pk_set, **kwargs):
+    """
+    Handle the cleanup of old custom field data when a CustomField is removed from one or more ContentTypes.
+    """
+    if action == 'post_remove':
+        instance.remove_stale_data(ContentType.objects.filter(pk__in=pk_set))
+
+
+def handle_cf_deleted(instance, **kwargs):
+    """
+    Handle the cleanup of old custom field data when a CustomField is deleted.
+    """
+    instance.remove_stale_data(instance.obj_type.all())
+
+
+m2m_changed.connect(handle_cf_removed_obj_types, sender=CustomField.obj_type.through)
+pre_delete.connect(handle_cf_deleted, sender=CustomField)
+
+
 #
 # Caching
 #