7699 use mixin for model

This commit is contained in:
Arthur Hanson 2024-10-24 11:19:47 -07:00
parent c73902c088
commit cfdab0e87f
3 changed files with 70 additions and 61 deletions

View File

@ -2,6 +2,7 @@ import json
from collections import defaultdict from collections import defaultdict
from functools import cached_property from functools import cached_property
from django.apps import apps
from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.fields import GenericRelation
from django.core.validators import ValidationError from django.core.validators import ValidationError
from django.db import models from django.db import models
@ -23,6 +24,7 @@ from utilities.views import register_model_view
__all__ = ( __all__ = (
'BookmarksMixin', 'BookmarksMixin',
'CachedLocationScopeMixin',
'ChangeLoggingMixin', 'ChangeLoggingMixin',
'CloningMixin', 'CloningMixin',
'ContactsMixin', 'ContactsMixin',
@ -580,6 +582,68 @@ class SyncedDataMixin(models.Model):
)) ))
class CachedLocationScopeMixin(models.Model):
"""
Cached associations for scope to enable efficient filtering - must define scope and scope_type on model
"""
_location = models.ForeignKey(
to='dcim.Location',
on_delete=models.CASCADE,
related_name='_%(class)ss',
blank=True,
null=True
)
_site = models.ForeignKey(
to='dcim.Site',
on_delete=models.CASCADE,
related_name='_%(class)ss',
blank=True,
null=True
)
_region = models.ForeignKey(
to='dcim.Region',
on_delete=models.CASCADE,
related_name='_%(class)ss',
blank=True,
null=True
)
_sitegroup = models.ForeignKey(
to='dcim.SiteGroup',
on_delete=models.CASCADE,
related_name='_%(class)ss',
blank=True,
null=True
)
class Meta:
abstract = True
def save(self, *args, **kwargs):
# Cache objects associated with the terminating object (for filtering)
self.cache_related_objects()
super().save(*args, **kwargs)
def cache_related_objects(self):
self._region = self._sitegroup = self._site = self._location = None
if self.scope_type:
scope_type = self.scope_type.model_class()
if scope_type == apps.get_model('dcim', 'region'):
self._region = self.scope
elif scope_type == apps.get_model('dcim', 'sitegroup'):
self._sitegroup = self.scope
elif scope_type == apps.get_model('dcim', 'site'):
self._region = self.scope.region
self._sitegroup = self.scope.group
self._site = self.scope
elif scope_type == apps.get_model('dcim', 'location'):
self._region = self.scope.site.region
self._sitegroup = self.scope.site.group
self._site = self.scope.site
self._location = self.scope
cache_related_objects.alters_data = True
# #
# Feature registration # Feature registration
# #

View File

@ -32,7 +32,7 @@ class Migration(migrations.Migration):
blank=True, blank=True,
null=True, null=True,
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name='_clusters', related_name='_%(class)ss',
to='dcim.location', to='dcim.location',
), ),
), ),
@ -43,7 +43,7 @@ class Migration(migrations.Migration):
blank=True, blank=True,
null=True, null=True,
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name='_clusters', related_name='_%(class)ss',
to='dcim.region', to='dcim.region',
), ),
), ),
@ -54,7 +54,7 @@ class Migration(migrations.Migration):
blank=True, blank=True,
null=True, null=True,
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name='_clusters', related_name='_%(class)ss',
to='dcim.site', to='dcim.site',
), ),
), ),
@ -65,7 +65,7 @@ class Migration(migrations.Migration):
blank=True, blank=True,
null=True, null=True,
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name='_clusters', related_name='_%(class)ss',
to='dcim.sitegroup', to='dcim.sitegroup',
), ),
), ),

View File

@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
from dcim.models import Device from dcim.models import Device
from netbox.models import OrganizationalModel, PrimaryModel from netbox.models import OrganizationalModel, PrimaryModel
from netbox.models.features import ContactsMixin from netbox.models.features import CachedLocationScopeMixin, ContactsMixin
from virtualization.choices import * from virtualization.choices import *
from virtualization.constants import CLUSTER_SCOPE_TYPES from virtualization.constants import CLUSTER_SCOPE_TYPES
@ -44,7 +44,7 @@ class ClusterGroup(ContactsMixin, OrganizationalModel):
verbose_name_plural = _('cluster groups') verbose_name_plural = _('cluster groups')
class Cluster(ContactsMixin, PrimaryModel): class Cluster(ContactsMixin, CachedLocationScopeMixin, PrimaryModel):
""" """
A cluster of VirtualMachines. Each Cluster may optionally be associated with one or more Devices. A cluster of VirtualMachines. Each Cluster may optionally be associated with one or more Devices.
""" """
@ -103,36 +103,6 @@ class Cluster(ContactsMixin, PrimaryModel):
related_query_name='cluster' related_query_name='cluster'
) )
# Cached associations to enable efficient filtering
_location = models.ForeignKey(
to='dcim.Location',
on_delete=models.CASCADE,
related_name='_clusters',
blank=True,
null=True
)
_site = models.ForeignKey(
to='dcim.Site',
on_delete=models.CASCADE,
related_name='_clusters',
blank=True,
null=True
)
_region = models.ForeignKey(
to='dcim.Region',
on_delete=models.CASCADE,
related_name='_clusters',
blank=True,
null=True
)
_sitegroup = models.ForeignKey(
to='dcim.SiteGroup',
on_delete=models.CASCADE,
related_name='_clusters',
blank=True,
null=True
)
clone_fields = ( clone_fields = (
'scope_type', 'scope_id', 'type', 'group', 'status', 'tenant', 'scope_type', 'scope_id', 'type', 'group', 'status', 'tenant',
) )
@ -180,28 +150,3 @@ class Cluster(ContactsMixin, PrimaryModel):
"{count} devices are assigned as hosts for this cluster but are not in site {site}" "{count} devices are assigned as hosts for this cluster but are not in site {site}"
).format(count=nonsite_devices, site=site) ).format(count=nonsite_devices, site=site)
}) })
def save(self, *args, **kwargs):
# Cache objects associated with the terminating object (for filtering)
self.cache_related_objects()
super().save(*args, **kwargs)
def cache_related_objects(self):
self._region = self._sitegroup = self._site = self._location = None
if self.scope_type:
scope_type = self.scope_type.model_class()
if scope_type == apps.get_model('dcim', 'region'):
self._region = self.scope
elif scope_type == apps.get_model('dcim', 'sitegroup'):
self._sitegroup = self.scope
elif scope_type == apps.get_model('dcim', 'site'):
self._region = self.scope.region
self._sitegroup = self.scope.group
self._site = self.scope
elif scope_type == apps.get_model('dcim', 'location'):
self._region = self.scope.site.region
self._sitegroup = self.scope.site.group
self._site = self.scope.site
self._location = self.scope
cache_related_objects.alters_data = True