mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-30 20:36:26 -06:00
Add denormalized relations
This commit is contained in:
parent
f28f1646b0
commit
f34818df71
@ -1,5 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
from netbox import denormalized
|
||||
|
||||
|
||||
class IPAMConfig(AppConfig):
|
||||
name = "ipam"
|
||||
@ -8,6 +10,16 @@ class IPAMConfig(AppConfig):
|
||||
def ready(self):
|
||||
from netbox.models.features import register_models
|
||||
from . import signals, search # noqa: F401
|
||||
from .models import Prefix
|
||||
|
||||
# Register models
|
||||
register_models(*self.get_models())
|
||||
|
||||
# Register denormalized fields
|
||||
denormalized.register(Prefix, '_site', {
|
||||
'_region': 'region',
|
||||
'_sitegroup': 'group',
|
||||
})
|
||||
denormalized.register(Prefix, '_location', {
|
||||
'_site': 'site',
|
||||
})
|
||||
|
@ -23,7 +23,7 @@ class Migration(migrations.Migration):
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Add the scope GenericForeignKey
|
||||
# Add the `scope` GenericForeignKey
|
||||
migrations.AddField(
|
||||
model_name='prefix',
|
||||
name='scope_id',
|
||||
@ -46,10 +46,4 @@ class Migration(migrations.Migration):
|
||||
code=copy_site_assignments,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
|
||||
# Delete the site ForeignKey
|
||||
migrations.RemoveField(
|
||||
model_name='prefix',
|
||||
name='site',
|
||||
),
|
||||
]
|
||||
|
61
netbox/ipam/migrations/0072_prefix_cached_relations.py
Normal file
61
netbox/ipam/migrations/0072_prefix_cached_relations.py
Normal file
@ -0,0 +1,61 @@
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def populate_denormalized_fields(apps, schema_editor):
|
||||
"""
|
||||
Copy site ForeignKey values to the scope GFK.
|
||||
"""
|
||||
Prefix = apps.get_model('ipam', 'Prefix')
|
||||
|
||||
prefixes = Prefix.objects.filter(site__isnull=False).prefetch_related('site')
|
||||
for prefix in prefixes:
|
||||
prefix._region_id = prefix.site.region_id
|
||||
prefix._sitegroup_id = prefix.site.group_id
|
||||
prefix._site_id = prefix.site_id
|
||||
# Note: Location cannot be set prior to migration
|
||||
|
||||
Prefix.objects.bulk_update(prefixes, ['_region', '_sitegroup', '_site'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0192_poweroutlet_color'),
|
||||
('ipam', '0071_prefix_scope'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='prefix',
|
||||
name='_location',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='prefix',
|
||||
name='_region',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.region'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='prefix',
|
||||
name='_site',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.site'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='prefix',
|
||||
name='_sitegroup',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.sitegroup'),
|
||||
),
|
||||
|
||||
# Populate denormalized FK values
|
||||
migrations.RunPython(
|
||||
code=populate_denormalized_fields,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
|
||||
# Delete the site ForeignKey
|
||||
migrations.RemoveField(
|
||||
model_name='prefix',
|
||||
name='site',
|
||||
),
|
||||
]
|
@ -1,4 +1,5 @@
|
||||
import netaddr
|
||||
from django.apps import apps
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
@ -270,6 +271,32 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, PrimaryModel):
|
||||
help_text=_("Treat as fully utilized")
|
||||
)
|
||||
|
||||
# Cached associations to enable efficient filtering
|
||||
_location = models.ForeignKey(
|
||||
to='dcim.Location',
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
_site = models.ForeignKey(
|
||||
to='dcim.Site',
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
_region = models.ForeignKey(
|
||||
to='dcim.Region',
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
_sitegroup = models.ForeignKey(
|
||||
to='dcim.SiteGroup',
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
|
||||
# Cached depth & child counts
|
||||
_depth = models.PositiveSmallIntegerField(
|
||||
default=0,
|
||||
@ -331,8 +358,37 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, PrimaryModel):
|
||||
# Clear host bits from prefix
|
||||
self.prefix = self.prefix.cidr
|
||||
|
||||
# Cache objects associated with the terminating object (for filtering)
|
||||
self.cache_related_objects()
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def cache_related_objects(self):
|
||||
if self.scope is None:
|
||||
return
|
||||
scope_type = self.scope_type.model_class()
|
||||
if scope_type == apps.get_model('dcim', 'region'):
|
||||
self._region = self.scope
|
||||
self._sitegroup = None
|
||||
self._site = None
|
||||
self._location = None
|
||||
elif scope_type == apps.get_model('dcim', 'sitegroup'):
|
||||
self._region = None
|
||||
self._sitegroup = self.scope
|
||||
self._site = None
|
||||
self._location = None
|
||||
elif scope_type == apps.get_model('dcim', 'site'):
|
||||
self._region = self.scope.region
|
||||
self._sitegroup = self.scope.group
|
||||
self._site = self.scope
|
||||
self._location = None
|
||||
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
|
||||
|
||||
@property
|
||||
def family(self):
|
||||
return self.prefix.version if self.prefix else None
|
||||
|
Loading…
Reference in New Issue
Block a user