Просмотр исходного кода

Closes #21016: Add missing MPTT tree indexes (#21432)

Upgrade django-mptt to 0.18.0 and add empty indexes tuple to MPTT model
Meta classes. The empty tuple triggers Django's migration detection for
indexes that django-mptt adds dynamically (see
django-mptt/django-mptt#682). We cannot define the indexes explicitly
because the MPTT fields don't exist when the Meta class is evaluated.

Affected models: Region, SiteGroup, Location, DeviceRole, Platform,
ModuleBay, InventoryItem, InventoryItemTemplate, TenantGroup,
ContactGroup, WirelessLANGroup
Jason Novinger 23 часов назад
Родитель
Сommit
0b7375136d

+ 49 - 0
netbox/dcim/migrations/0226_add_mptt_tree_indexes.py

@@ -0,0 +1,49 @@
+# Generated by Django 5.2.10 on 2026-02-13 13:36
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0002_remove_content_type_name'),
+        ('dcim', '0225_gfk_indexes'),
+        ('extras', '0134_owner'),
+        ('tenancy', '0022_add_comments_to_organizationalmodel'),
+        ('users', '0015_owner'),
+    ]
+
+    operations = [
+        migrations.AddIndex(
+            model_name='devicerole',
+            index=models.Index(fields=['tree_id', 'lft'], name='dcim_devicerole_tree_id_lfbf11'),
+        ),
+        migrations.AddIndex(
+            model_name='inventoryitem',
+            index=models.Index(fields=['tree_id', 'lft'], name='dcim_inventoryitem_tree_id975c'),
+        ),
+        migrations.AddIndex(
+            model_name='inventoryitemtemplate',
+            index=models.Index(fields=['tree_id', 'lft'], name='dcim_inventoryitemtemplatedee0'),
+        ),
+        migrations.AddIndex(
+            model_name='location',
+            index=models.Index(fields=['tree_id', 'lft'], name='dcim_location_tree_id_lft_idx'),
+        ),
+        migrations.AddIndex(
+            model_name='modulebay',
+            index=models.Index(fields=['tree_id', 'lft'], name='dcim_modulebay_tree_id_lft_idx'),
+        ),
+        migrations.AddIndex(
+            model_name='platform',
+            index=models.Index(fields=['tree_id', 'lft'], name='dcim_platform_tree_id_lft_idx'),
+        ),
+        migrations.AddIndex(
+            model_name='region',
+            index=models.Index(fields=['tree_id', 'lft'], name='dcim_region_tree_id_lft_idx'),
+        ),
+        migrations.AddIndex(
+            model_name='sitegroup',
+            index=models.Index(fields=['tree_id', 'lft'], name='dcim_sitegroup_tree_id_lft_idx'),
+        ),
+    ]

+ 3 - 0
netbox/dcim/models/device_components.py

@@ -1263,6 +1263,9 @@ class ModuleBay(ModularComponentModel, TrackingModelMixin, MPTTModel):
     clone_fields = ('device',)
 
     class Meta(ModularComponentModel.Meta):
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         constraints = (
             models.UniqueConstraint(
                 fields=('device', 'module', 'name'),

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

@@ -401,6 +401,9 @@ class DeviceRole(NestedGroupModel):
 
     class Meta:
         ordering = ('name',)
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         constraints = (
             models.UniqueConstraint(
                 fields=('parent', 'name'),
@@ -452,6 +455,9 @@ class Platform(NestedGroupModel):
 
     class Meta:
         ordering = ('name',)
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         verbose_name = _('platform')
         verbose_name_plural = _('platforms')
         constraints = (

+ 9 - 0
netbox/dcim/models/sites.py

@@ -44,6 +44,9 @@ class Region(ContactsMixin, NestedGroupModel):
     )
 
     class Meta:
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         constraints = (
             models.UniqueConstraint(
                 fields=('parent', 'name'),
@@ -100,6 +103,9 @@ class SiteGroup(ContactsMixin, NestedGroupModel):
     )
 
     class Meta:
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         constraints = (
             models.UniqueConstraint(
                 fields=('parent', 'name'),
@@ -318,6 +324,9 @@ class Location(ContactsMixin, ImageAttachmentsMixin, NestedGroupModel):
 
     class Meta:
         ordering = ['site', 'name']
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         constraints = (
             models.UniqueConstraint(
                 fields=('site', 'parent', 'name'),

+ 4 - 0
netbox/netbox/models/__init__.py

@@ -143,6 +143,10 @@ class NestedGroupModel(OwnerMixin, NetBoxModel, MPTTModel):
     """
     Base model for objects which are used to form a hierarchy (regions, locations, etc.). These models nest
     recursively using MPTT. Within each parent, each child instance must have a unique name.
+
+    Note: django-mptt injects the (tree_id, lft) index dynamically, but Django's migration autodetector won't
+    detect it unless concrete subclasses explicitly declare Meta.indexes (even as an empty tuple). See #21016
+    and django-mptt/django-mptt#682.
     """
     parent = TreeForeignKey(
         to='self',

+ 23 - 0
netbox/tenancy/migrations/0023_add_mptt_tree_indexes.py

@@ -0,0 +1,23 @@
+# Generated by Django 5.2.10 on 2026-02-13 13:36
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('extras', '0134_owner'),
+        ('tenancy', '0022_add_comments_to_organizationalmodel'),
+        ('users', '0015_owner'),
+    ]
+
+    operations = [
+        migrations.AddIndex(
+            model_name='contactgroup',
+            index=models.Index(fields=['tree_id', 'lft'], name='tenancy_contactgroup_tree_d2ce'),
+        ),
+        migrations.AddIndex(
+            model_name='tenantgroup',
+            index=models.Index(fields=['tree_id', 'lft'], name='tenancy_tenantgroup_tree_ifebc'),
+        ),
+    ]

+ 3 - 0
netbox/tenancy/models/contacts.py

@@ -22,6 +22,9 @@ class ContactGroup(NestedGroupModel):
     """
     class Meta:
         ordering = ['name']
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         constraints = (
             models.UniqueConstraint(
                 fields=('parent', 'name'),

+ 3 - 0
netbox/tenancy/models/tenants.py

@@ -29,6 +29,9 @@ class TenantGroup(NestedGroupModel):
 
     class Meta:
         ordering = ['name']
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         verbose_name = _('tenant group')
         verbose_name_plural = _('tenant groups')
 

+ 19 - 0
netbox/wireless/migrations/0018_add_mptt_tree_indexes.py

@@ -0,0 +1,19 @@
+# Generated by Django 5.2.10 on 2026-02-13 13:36
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('extras', '0134_owner'),
+        ('users', '0015_owner'),
+        ('wireless', '0017_gfk_indexes'),
+    ]
+
+    operations = [
+        migrations.AddIndex(
+            model_name='wirelesslangroup',
+            index=models.Index(fields=['tree_id', 'lft'], name='wireless_wirelesslangroup_fbcd'),
+        ),
+    ]

+ 3 - 0
netbox/wireless/models.py

@@ -63,6 +63,9 @@ class WirelessLANGroup(NestedGroupModel):
 
     class Meta:
         ordering = ('name', 'pk')
+        # Empty tuple triggers Django migration detection for MPTT indexes
+        # (see #21016, django-mptt/django-mptt#682)
+        indexes = ()
         constraints = (
             models.UniqueConstraint(
                 fields=('parent', 'name'),

+ 1 - 1
requirements.txt

@@ -5,7 +5,7 @@ django-debug-toolbar==6.2.0
 django-filter==25.2
 django-graphiql-debug-toolbar==0.2.0
 django-htmx==1.27.0
-django-mptt==0.17.0
+django-mptt==0.18.0
 django-pglocks==1.0.4
 django-prometheus==2.4.1
 django-redis==6.0.0