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

Merge pull request #8510 from netbox-community/8032-django-40

Closes #8032: Upgrade to Django 4.0
Jeremy Stretch 4 лет назад
Родитель
Сommit
733a9bb2e1

+ 9 - 9
netbox/dcim/migrations/0002_squashed.py

@@ -58,7 +58,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='rearporttemplate',
             name='device_type',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rearporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AddField(
             model_name='rearport',
@@ -73,7 +73,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='rearport',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rearports', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='rearport',
@@ -128,7 +128,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='powerporttemplate',
             name='device_type',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='powerporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AddField(
             model_name='powerport',
@@ -148,7 +148,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='powerport',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='powerports', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='powerport',
@@ -173,7 +173,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='poweroutlettemplate',
             name='device_type',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='poweroutlettemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AddField(
             model_name='poweroutlettemplate',
@@ -198,7 +198,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='poweroutlet',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='poweroutlets', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='poweroutlet',
@@ -258,7 +258,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='inventoryitem',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inventoryitems', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='inventoryitem',
@@ -278,7 +278,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='interfacetemplate',
             name='device_type',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interfacetemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AddField(
             model_name='interface',
@@ -298,7 +298,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='interface',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interfaces', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='interface',

+ 8 - 8
netbox/dcim/migrations/0003_squashed_0130.py

@@ -165,7 +165,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='frontporttemplate',
             name='device_type',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='frontporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AddField(
             model_name='frontporttemplate',
@@ -185,7 +185,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='frontport',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='frontports', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='frontport',
@@ -210,12 +210,12 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='devicebaytemplate',
             name='device_type',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='devicebaytemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AddField(
             model_name='devicebay',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='devicebays', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='devicebay',
@@ -290,7 +290,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='consoleserverporttemplate',
             name='device_type',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='consoleserverporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AddField(
             model_name='consoleserverport',
@@ -310,7 +310,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='consoleserverport',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='consoleserverports', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='consoleserverport',
@@ -320,7 +320,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='consoleporttemplate',
             name='device_type',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='consoleporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AddField(
             model_name='consoleport',
@@ -340,7 +340,7 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='consoleport',
             name='device',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='consoleports', to='dcim.device'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device'),
         ),
         migrations.AddField(
             model_name='consoleport',

+ 23 - 23
netbox/dcim/migrations/0146_modules.py

@@ -45,37 +45,37 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name='consoleporttemplate',
             name='device_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='consoleporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AlterField(
             model_name='consoleserverporttemplate',
             name='device_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='consoleserverporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AlterField(
             model_name='frontporttemplate',
             name='device_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='frontporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AlterField(
             model_name='interfacetemplate',
             name='device_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interfacetemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AlterField(
             model_name='poweroutlettemplate',
             name='device_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='poweroutlettemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AlterField(
             model_name='powerporttemplate',
             name='device_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='powerporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.AlterField(
             model_name='rearporttemplate',
             name='device_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rearporttemplates', to='dcim.devicetype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
         ),
         migrations.CreateModel(
             name='ModuleType',
@@ -107,7 +107,7 @@ class Migration(migrations.Migration):
                 ('label', models.CharField(blank=True, max_length=64)),
                 ('position', models.CharField(blank=True, max_length=30)),
                 ('description', models.CharField(blank=True, max_length=200)),
-                ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modulebays', to='dcim.device')),
+                ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device')),
                 ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
             ],
             options={
@@ -138,72 +138,72 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='consoleport',
             name='module',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='consoleports', to='dcim.module'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
         ),
         migrations.AddField(
             model_name='consoleporttemplate',
             name='module_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='consoleporttemplates', to='dcim.moduletype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
         ),
         migrations.AddField(
             model_name='consoleserverport',
             name='module',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='consoleserverports', to='dcim.module'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
         ),
         migrations.AddField(
             model_name='consoleserverporttemplate',
             name='module_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='consoleserverporttemplates', to='dcim.moduletype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
         ),
         migrations.AddField(
             model_name='frontport',
             name='module',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='frontports', to='dcim.module'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
         ),
         migrations.AddField(
             model_name='frontporttemplate',
             name='module_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='frontporttemplates', to='dcim.moduletype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
         ),
         migrations.AddField(
             model_name='interface',
             name='module',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interfaces', to='dcim.module'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
         ),
         migrations.AddField(
             model_name='interfacetemplate',
             name='module_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interfacetemplates', to='dcim.moduletype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
         ),
         migrations.AddField(
             model_name='poweroutlet',
             name='module',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='poweroutlets', to='dcim.module'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
         ),
         migrations.AddField(
             model_name='poweroutlettemplate',
             name='module_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='poweroutlettemplates', to='dcim.moduletype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
         ),
         migrations.AddField(
             model_name='powerport',
             name='module',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='powerports', to='dcim.module'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
         ),
         migrations.AddField(
             model_name='powerporttemplate',
             name='module_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='powerporttemplates', to='dcim.moduletype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
         ),
         migrations.AddField(
             model_name='rearport',
             name='module',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rearports', to='dcim.module'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
         ),
         migrations.AddField(
             model_name='rearporttemplate',
             name='module_type',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rearporttemplates', to='dcim.moduletype'),
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
         ),
         migrations.AlterUniqueTogether(
             name='consoleporttemplate',
@@ -244,7 +244,7 @@ class Migration(migrations.Migration):
                 ('label', models.CharField(blank=True, max_length=64)),
                 ('position', models.CharField(blank=True, max_length=30)),
                 ('description', models.CharField(blank=True, max_length=200)),
-                ('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modulebaytemplates', to='dcim.devicetype')),
+                ('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype')),
             ],
             options={
                 'ordering': ('device_type', '_name'),

+ 1 - 1
netbox/dcim/migrations/0149_inventoryitem_templates.py

@@ -30,7 +30,7 @@ class Migration(migrations.Migration):
                 ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
                 ('level', models.PositiveIntegerField(editable=False)),
                 ('component_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(('app_label', 'dcim'), ('model__in', ('consoleporttemplate', 'consoleserverporttemplate', 'frontporttemplate', 'interfacetemplate', 'poweroutlettemplate', 'powerporttemplate', 'rearporttemplate'))), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')),
-                ('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inventoryitemtemplates', to='dcim.devicetype')),
+                ('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype')),
                 ('manufacturer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_item_templates', to='dcim.manufacturer')),
                 ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child_items', to='dcim.inventoryitemtemplate')),
                 ('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_item_templates', to='dcim.inventoryitemrole')),

+ 2 - 2
netbox/extras/migrations/0001_squashed.py

@@ -99,8 +99,8 @@ class Migration(migrations.Migration):
             fields=[
                 ('object_id', models.IntegerField(db_index=True)),
                 ('id', models.BigAutoField(primary_key=True, serialize=False)),
-                ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='extras_taggeditem_tagged_items', to='contenttypes.contenttype')),
-                ('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='extras_taggeditem_items', to='extras.tag')),
+                ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_tagged_items', to='contenttypes.contenttype')),
+                ('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_items', to='extras.tag')),
             ],
         ),
         migrations.CreateModel(

+ 11 - 11
netbox/extras/migrations/0002_squashed_0059.py

@@ -75,57 +75,57 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='configcontext',
             name='cluster_groups',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_cluster_groups_+', to='virtualization.ClusterGroup'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='virtualization.ClusterGroup'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='clusters',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_clusters_+', to='virtualization.Cluster'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='virtualization.Cluster'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='device_types',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_device_types_+', to='dcim.DeviceType'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='dcim.DeviceType'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='platforms',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_platforms_+', to='dcim.Platform'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='dcim.Platform'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='regions',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_regions_+', to='dcim.Region'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='dcim.Region'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='roles',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_roles_+', to='dcim.DeviceRole'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='dcim.DeviceRole'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='site_groups',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_site_groups_+', to='dcim.SiteGroup'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='dcim.SiteGroup'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='sites',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_sites_+', to='dcim.Site'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='dcim.Site'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='tags',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_tags_+', to='extras.Tag'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='extras.Tag'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='tenant_groups',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_tenant_groups_+', to='tenancy.TenantGroup'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='tenancy.TenantGroup'),
         ),
         migrations.AddField(
             model_name='configcontext',
             name='tenants',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_tenants_+', to='tenancy.Tenant'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='tenancy.Tenant'),
         ),
         migrations.AlterUniqueTogether(
             name='webhook',

+ 1 - 1
netbox/extras/migrations/0068_configcontext_cluster_types.py

@@ -12,6 +12,6 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='configcontext',
             name='cluster_types',
-            field=models.ManyToManyField(blank=True, related_name='_extras_configcontext_cluster_types_+', to='virtualization.ClusterType'),
+            field=models.ManyToManyField(blank=True, related_name='+', to='virtualization.ClusterType'),
         ),
     ]

+ 1 - 1
netbox/extras/querysets.py

@@ -82,7 +82,7 @@ class ConfigContextModelQuerySet(RestrictedQuerySet):
                     self._get_config_context_filters()
                 ).annotate(
                     _data=EmptyGroupByJSONBAgg('data', ordering=['weight', 'name'])
-                ).values("_data")
+                ).values("_data").order_by()
             )
         ).distinct()
 

+ 3 - 7
netbox/netbox/views/generic/object_views.py

@@ -9,7 +9,6 @@ from django.forms.widgets import HiddenInput
 from django.shortcuts import redirect, render
 from django.urls import reverse
 from django.utils.html import escape
-from django.utils.http import is_safe_url
 from django.utils.safestring import mark_safe
 
 from extras.signals import clear_webhooks
@@ -259,9 +258,7 @@ class ObjectImportView(GetReturnURLMixin, BaseObjectView):
                 if '_addanother' in request.POST:
                     return redirect(request.get_full_path())
 
-                return_url = form.cleaned_data.get('return_url')
-                if return_url is not None and is_safe_url(url=return_url, allowed_hosts=request.get_host()):
-                    return redirect(return_url)
+                self.get_return_url(request, obj)
                 return redirect(self.get_return_url(request, obj))
 
             else:
@@ -507,10 +504,9 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
             messages.success(request, msg)
 
             return_url = form.cleaned_data.get('return_url')
-            if return_url is not None and is_safe_url(url=return_url, allowed_hosts=request.get_host()):
+            if return_url and return_url.startswith('/'):
                 return redirect(return_url)
-            else:
-                return redirect(self.get_return_url(request, obj))
+            return redirect(self.get_return_url(request, obj))
 
         else:
             logger.debug("Form validation failed")

+ 9 - 10
netbox/users/views.py

@@ -10,7 +10,6 @@ from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404, redirect, render
 from django.urls import reverse
 from django.utils.decorators import method_decorator
-from django.utils.http import is_safe_url
 from django.views.decorators.debug import sensitive_post_parameters
 from django.views.generic import View
 from social_core.backends.utils import load_backends
@@ -78,17 +77,17 @@ class LoginView(View):
         })
 
     def redirect_to_next(self, request, logger):
-        if request.method == "POST":
-            redirect_to = request.POST.get('next', settings.LOGIN_REDIRECT_URL)
-        else:
-            redirect_to = request.GET.get('next', settings.LOGIN_REDIRECT_URL)
+        data = request.POST if request.method == "POST" else request.GET
+        redirect_url = data.get('next', settings.LOGIN_REDIRECT_URL)
 
-        if redirect_to and not is_safe_url(url=redirect_to, allowed_hosts=request.get_host()):
-            logger.warning(f"Ignoring unsafe 'next' URL passed to login form: {redirect_to}")
-            redirect_to = reverse('home')
+        if redirect_url and redirect_url.startswith('/'):
+            logger.debug(f"Redirecting user to {redirect_url}")
+        else:
+            if redirect_url:
+                logger.warning(f"Ignoring unsafe 'next' URL passed to login form: {redirect_url}")
+            redirect_url = reverse('home')
 
-        logger.debug(f"Redirecting user to {redirect_to}")
-        return HttpResponseRedirect(redirect_to)
+        return HttpResponseRedirect(redirect_url)
 
 
 class LogoutView(View):

+ 3 - 6
netbox/utilities/views.py

@@ -1,10 +1,7 @@
 from django.contrib.auth.mixins import AccessMixin
 from django.core.exceptions import ImproperlyConfigured
-from django.shortcuts import get_object_or_404, redirect
 from django.urls import reverse
 from django.urls.exceptions import NoReverseMatch
-from django.utils.http import is_safe_url
-from django.views.generic import View
 
 from .permissions import resolve_permission
 
@@ -103,9 +100,9 @@ class GetReturnURLMixin:
 
         # First, see if `return_url` was specified as a query parameter or form data. Use this URL only if it's
         # considered safe.
-        query_param = request.GET.get('return_url') or request.POST.get('return_url')
-        if query_param and is_safe_url(url=query_param, allowed_hosts=request.get_host()):
-            return query_param
+        return_url = request.GET.get('return_url') or request.POST.get('return_url')
+        if return_url and return_url.startswith('/'):
+            return return_url
 
         # Next, check if the object being modified (if any) has an absolute URL.
         if obj is not None and obj.pk and hasattr(obj, 'get_absolute_url'):

+ 5 - 3
requirements.txt

@@ -1,4 +1,4 @@
-Django==3.2.12
+Django==4.0.2
 django-cors-headers==3.11.0
 django-debug-toolbar==3.2.4
 django-filter==21.1
@@ -9,11 +9,13 @@ django-prometheus==2.2.0
 django-redis==5.2.0
 django-rq==2.5.1
 django-tables2==2.4.1
-django-taggit==2.0.0
+django-taggit==2.1.0
 django-timezone-field==4.2.3
 djangorestframework==3.12.4
 drf-yasg[validation]==1.20.0
-graphene_django==2.15.0
+#graphene_django==2.15.0
+# Installing from PR origin temporarily
+git+git://github.com/graphql-python/graphene-django.git@v2
 gunicorn==20.1.0
 Jinja2==3.0.3
 Markdown==3.3.6