Jeremy Stretch 4 недель назад
Родитель
Сommit
5dd5d65d74

+ 9 - 0
netbox/dcim/apps.py

@@ -29,6 +29,15 @@ class DCIMConfig(AppConfig):
         denormalized.register(CableTermination, '_location', {
             '_site': 'site',
         })
+        denormalized.register(Device, 'virtual_chassis', {
+            '_virtual_chassis_name': 'name',
+        })
+        denormalized.register(Device, 'primary_ip4', {
+            '_primary_ip4_address': 'address',
+        })
+        denormalized.register(Device, 'primary_ip6', {
+            '_primary_ip6_address': 'address',
+        })
 
         # Register counters
         connect_counters(Device, DeviceType, ModuleType, RackType, VirtualChassis)

+ 4 - 3
netbox/dcim/filtersets.py

@@ -1331,13 +1331,14 @@ class DeviceFilterSet(
             return queryset
         return queryset.filter(
             Q(name__icontains=value) |
-            Q(virtual_chassis__name__icontains=value) |
             Q(serial__icontains=value.strip()) |
             Q(asset_tag__icontains=value.strip()) |
             Q(description__icontains=value.strip()) |
             Q(comments__icontains=value) |
-            Q(primary_ip4__address__startswith=value) |
-            Q(primary_ip6__address__startswith=value)
+            # Denormalized fields
+            Q(_virtual_chassis_name__icontains=value) |
+            Q(_primary_ip4_address__startswith=value) |
+            Q(_primary_ip6_address__startswith=value)
         ).distinct()
 
     def _has_primary_ip(self, queryset, name, value):

+ 1 - 1
netbox/dcim/graphql/types.py

@@ -224,7 +224,7 @@ class ConsoleServerPortTemplateType(ModularComponentTemplateType):
 
 @strawberry_django.type(
     models.Device,
-    fields='__all__',
+    exclude=['_virtual_chassis_name', '_primary_ip4_address', '_primary_ip6_address'],
     filters=DeviceFilter,
     pagination=True
 )

+ 46 - 0
netbox/dcim/migrations/0226_denormalize_search_attrs.py

@@ -0,0 +1,46 @@
+from django.db import migrations, models
+from django.db.models import Q
+
+import ipam.fields
+
+
+def backfill_denormalized_fields(apps, schema_editor):
+    Device = apps.get_model('dcim', 'Device')
+
+    # TODO: Optimize for bulk operations
+    for device in Device.objects.filter(
+        Q(virtual_chassis__isnull=False) | Q(primary_ip4__isnull=False) | Q(primary_ip6__isnull=False)
+    ):
+        device._virtual_chassis_name = device.virtual_chassis.name if device.virtual_chassis else ''
+        device._primary_ip4_address = device.primary_ip4.address if device.primary_ip4 else None
+        device._primary_ip6_address = device.primary_ip6.address if device.primary_ip6 else None
+        device.save()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dcim', '0225_gfk_indexes'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='device',
+            name='_primary_ip4_address',
+            field=ipam.fields.IPAddressField(blank=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='device',
+            name='_primary_ip6_address',
+            field=ipam.fields.IPAddressField(blank=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='device',
+            name='_virtual_chassis_name',
+            field=models.CharField(blank=True),
+        ),
+        migrations.RunPython(
+            code=backfill_denormalized_fields,
+            reverse_code=migrations.RunPython.noop
+        ),
+    ]

+ 14 - 0
netbox/dcim/models/devices.py

@@ -21,6 +21,7 @@ from dcim.fields import MACAddressField
 from dcim.utils import create_port_mappings, update_interface_bridges
 from extras.models import ConfigContextModel, CustomField
 from extras.querysets import ConfigContextModelQuerySet
+from ipam.fields import IPAddressField
 from netbox.choices import ColorChoices
 from netbox.config import ConfigItem
 from netbox.models import NestedGroupModel, OrganizationalModel, PrimaryModel
@@ -673,6 +674,19 @@ class Device(
         related_query_name='device',
     )
 
+    # Denormalized fields
+    _virtual_chassis_name = models.CharField(
+        blank=True,
+    )
+    _primary_ip4_address = IPAddressField(
+        blank=True,
+        null=True,
+    )
+    _primary_ip6_address = IPAddressField(
+        blank=True,
+        null=True,
+    )
+
     # Counter fields
     console_port_count = CounterCacheField(
         to_model='dcim.ConsolePort',