From ef75f7e65030121e22a63e30e1c76f4d1f31c9ba Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 1 Feb 2022 13:01:28 -0500 Subject: [PATCH 1/5] Upgrade to Django 4.0 --- requirements.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index cb6d4b6c9..26a0151e0 100644 --- a/requirements.txt +++ b/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/MisterGlass/graphene-django.git gunicorn==20.1.0 Jinja2==3.0.3 Markdown==3.3.6 From 7611cfddae9f127ccad934923198bf09fe7ddb95 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 1 Feb 2022 13:20:03 -0500 Subject: [PATCH 2/5] Tweak related names in old migrations to avoid creating new ones --- netbox/dcim/migrations/0002_squashed.py | 18 ++++---- netbox/dcim/migrations/0003_squashed_0130.py | 16 +++---- netbox/dcim/migrations/0146_modules.py | 46 +++++++++---------- .../0149_inventoryitem_templates.py | 2 +- netbox/extras/migrations/0001_squashed.py | 4 +- .../extras/migrations/0002_squashed_0059.py | 22 ++++----- .../0068_configcontext_cluster_types.py | 2 +- 7 files changed, 55 insertions(+), 55 deletions(-) diff --git a/netbox/dcim/migrations/0002_squashed.py b/netbox/dcim/migrations/0002_squashed.py index a1b6db30a..c7325210e 100644 --- a/netbox/dcim/migrations/0002_squashed.py +++ b/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', diff --git a/netbox/dcim/migrations/0003_squashed_0130.py b/netbox/dcim/migrations/0003_squashed_0130.py index 48ea238d9..592aaf9a8 100644 --- a/netbox/dcim/migrations/0003_squashed_0130.py +++ b/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', diff --git a/netbox/dcim/migrations/0146_modules.py b/netbox/dcim/migrations/0146_modules.py index cdc7960a4..0b0282c80 100644 --- a/netbox/dcim/migrations/0146_modules.py +++ b/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'), diff --git a/netbox/dcim/migrations/0149_inventoryitem_templates.py b/netbox/dcim/migrations/0149_inventoryitem_templates.py index 7ef347680..f0b1f3cff 100644 --- a/netbox/dcim/migrations/0149_inventoryitem_templates.py +++ b/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')), diff --git a/netbox/extras/migrations/0001_squashed.py b/netbox/extras/migrations/0001_squashed.py index 916dab7b4..ea89400e1 100644 --- a/netbox/extras/migrations/0001_squashed.py +++ b/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( diff --git a/netbox/extras/migrations/0002_squashed_0059.py b/netbox/extras/migrations/0002_squashed_0059.py index 9098d286f..98bed255a 100644 --- a/netbox/extras/migrations/0002_squashed_0059.py +++ b/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', diff --git a/netbox/extras/migrations/0068_configcontext_cluster_types.py b/netbox/extras/migrations/0068_configcontext_cluster_types.py index 40c7887e3..abe90013e 100644 --- a/netbox/extras/migrations/0068_configcontext_cluster_types.py +++ b/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'), ), ] From 630ff2abb4f9368bb2329579b0b0d6c00af3bd3d Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 1 Feb 2022 13:31:53 -0500 Subject: [PATCH 3/5] Remove dependency on is_safe_url() --- netbox/netbox/views/generic/object_views.py | 10 +++------- netbox/users/views.py | 19 +++++++++---------- netbox/utilities/views.py | 9 +++------ 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index 316c3a1ee..a078f565c 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/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") diff --git a/netbox/users/views.py b/netbox/users/views.py index cd3c34aa9..43c65eada 100644 --- a/netbox/users/views.py +++ b/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) + data = request.POST if request.method == "POST" else request.GET + redirect_url = data.get('next', settings.LOGIN_REDIRECT_URL) + + if redirect_url and redirect_url.startswith('/'): + logger.debug(f"Redirecting user to {redirect_url}") else: - redirect_to = request.GET.get('next', settings.LOGIN_REDIRECT_URL) + if redirect_url: + logger.warning(f"Ignoring unsafe 'next' URL passed to login form: {redirect_url}") + redirect_url = reverse('home') - 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') - - logger.debug(f"Redirecting user to {redirect_to}") - return HttpResponseRedirect(redirect_to) + return HttpResponseRedirect(redirect_url) class LogoutView(View): diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index efea0b867..858e7b491 100644 --- a/netbox/utilities/views.py +++ b/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'): From 0e95ca7b69148525cedd91c99dfaa81fc3d68332 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 1 Feb 2022 14:10:25 -0500 Subject: [PATCH 4/5] Fix ProgrammingError exception when annotating config context data --- netbox/extras/querysets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/extras/querysets.py b/netbox/extras/querysets.py index 982f33d02..21727d3d4 100644 --- a/netbox/extras/querysets.py +++ b/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() From 9ac769e4f851356cdcd4991542d40cba47339bf7 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 7 Feb 2022 11:32:02 -0500 Subject: [PATCH 5/5] Pull graphene-django from v2 branch --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 26a0151e0..1239ed205 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ djangorestframework==3.12.4 drf-yasg[validation]==1.20.0 #graphene_django==2.15.0 # Installing from PR origin temporarily -git+git://github.com/MisterGlass/graphene-django.git +git+git://github.com/graphql-python/graphene-django.git@v2 gunicorn==20.1.0 Jinja2==3.0.3 Markdown==3.3.6