From 5f43eabab1a5f727fc98ec6ba297b52d09788917 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 1 Mar 2024 16:54:01 -0500 Subject: [PATCH] Rename ContactAssignment.content_type to object_type --- netbox/netbox/models/features.py | 4 +- netbox/tenancy/api/serializers.py | 6 +-- netbox/tenancy/filtersets.py | 4 +- netbox/tenancy/forms/filtersets.py | 4 +- netbox/tenancy/forms/model_forms.py | 4 +- ...5_contactassignment_rename_content_type.py | 40 +++++++++++++++++++ netbox/tenancy/models/contacts.py | 14 +++---- netbox/tenancy/tables/contacts.py | 6 +-- netbox/tenancy/tests/test_api.py | 6 +-- netbox/tenancy/tests/test_filtersets.py | 4 +- netbox/tenancy/tests/test_views.py | 6 +-- netbox/tenancy/views.py | 8 ++-- 12 files changed, 74 insertions(+), 32 deletions(-) create mode 100644 netbox/tenancy/migrations/0015_contactassignment_rename_content_type.py diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index c8137ec66..74b24aa85 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -343,7 +343,9 @@ class ContactsMixin(models.Model): Enables the assignments of Contacts (via ContactAssignment). """ contacts = GenericRelation( - to='tenancy.ContactAssignment' + to='tenancy.ContactAssignment', + content_type_field='object_type', + object_id_field='object_id' ) class Meta: diff --git a/netbox/tenancy/api/serializers.py b/netbox/tenancy/api/serializers.py index 325d3b439..5e7382b70 100644 --- a/netbox/tenancy/api/serializers.py +++ b/netbox/tenancy/api/serializers.py @@ -100,7 +100,7 @@ class ContactSerializer(NetBoxModelSerializer): class ContactAssignmentSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactassignment-detail') - content_type = ContentTypeField( + object_type = ContentTypeField( queryset=ContentType.objects.all() ) object = serializers.SerializerMethodField(read_only=True) @@ -111,13 +111,13 @@ class ContactAssignmentSerializer(NetBoxModelSerializer): class Meta: model = ContactAssignment fields = [ - 'id', 'url', 'display', 'content_type', 'object_id', 'object', 'contact', 'role', 'priority', 'tags', + 'id', 'url', 'display', 'object_type', 'object_id', 'object', 'contact', 'role', 'priority', 'tags', 'custom_fields', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'contact', 'role', 'priority') @extend_schema_field(OpenApiTypes.OBJECT) def get_object(self, instance): - serializer = get_serializer_for_model(instance.content_type.model_class(), prefix=NESTED_SERIALIZER_PREFIX) + serializer = get_serializer_for_model(instance.object_type.model_class(), prefix=NESTED_SERIALIZER_PREFIX) context = {'request': self.context['request']} return serializer(instance.object, context=context).data diff --git a/netbox/tenancy/filtersets.py b/netbox/tenancy/filtersets.py index 8079b4035..295d20774 100644 --- a/netbox/tenancy/filtersets.py +++ b/netbox/tenancy/filtersets.py @@ -86,7 +86,7 @@ class ContactAssignmentFilterSet(NetBoxModelFilterSet): method='search', label=_('Search'), ) - content_type = ContentTypeFilter() + object_type = ContentTypeFilter() contact_id = django_filters.ModelMultipleChoiceFilter( queryset=Contact.objects.all(), label=_('Contact (ID)'), @@ -118,7 +118,7 @@ class ContactAssignmentFilterSet(NetBoxModelFilterSet): class Meta: model = ContactAssignment - fields = ['id', 'content_type_id', 'object_id', 'priority', 'tag'] + fields = ['id', 'object_type_id', 'object_id', 'priority', 'tag'] def search(self, queryset, name, value): if not value.strip(): diff --git a/netbox/tenancy/forms/filtersets.py b/netbox/tenancy/forms/filtersets.py index e5f038923..fbd0f2ad0 100644 --- a/netbox/tenancy/forms/filtersets.py +++ b/netbox/tenancy/forms/filtersets.py @@ -83,9 +83,9 @@ class ContactAssignmentFilterForm(NetBoxModelFilterSetForm): model = ContactAssignment fieldsets = ( (None, ('q', 'filter_id', 'tag')), - (_('Assignment'), ('content_type_id', 'group_id', 'contact_id', 'role_id', 'priority')), + (_('Assignment'), ('object_type_id', 'group_id', 'contact_id', 'role_id', 'priority')), ) - content_type_id = ContentTypeMultipleChoiceField( + object_type_id = ContentTypeMultipleChoiceField( queryset=ObjectType.objects.with_feature('contacts'), required=False, label=_('Object type') diff --git a/netbox/tenancy/forms/model_forms.py b/netbox/tenancy/forms/model_forms.py index 9a53eba17..140d9cf9a 100644 --- a/netbox/tenancy/forms/model_forms.py +++ b/netbox/tenancy/forms/model_forms.py @@ -143,9 +143,9 @@ class ContactAssignmentForm(NetBoxModelForm): class Meta: model = ContactAssignment fields = ( - 'content_type', 'object_id', 'group', 'contact', 'role', 'priority', 'tags' + 'object_type', 'object_id', 'group', 'contact', 'role', 'priority', 'tags' ) widgets = { - 'content_type': forms.HiddenInput(), + 'object_type': forms.HiddenInput(), 'object_id': forms.HiddenInput(), } diff --git a/netbox/tenancy/migrations/0015_contactassignment_rename_content_type.py b/netbox/tenancy/migrations/0015_contactassignment_rename_content_type.py new file mode 100644 index 000000000..58b14e10f --- /dev/null +++ b/netbox/tenancy/migrations/0015_contactassignment_rename_content_type.py @@ -0,0 +1,40 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('extras', '0111_rename_content_types'), + ('tenancy', '0014_contactassignment_ordering'), + ] + + operations = [ + migrations.RemoveConstraint( + model_name='contactassignment', + name='tenancy_contactassignment_unique_object_contact_role', + ), + migrations.RemoveIndex( + model_name='contactassignment', + name='tenancy_con_content_693ff4_idx', + ), + migrations.RenameField( + model_name='contactassignment', + old_name='content_type', + new_name='object_type', + ), + migrations.AddIndex( + model_name='contactassignment', + index=models.Index( + fields=['object_type', 'object_id'], + name='tenancy_con_object__6f20f7_idx' + ), + ), + migrations.AddConstraint( + model_name='contactassignment', + constraint=models.UniqueConstraint( + fields=('object_type', 'object_id', 'contact', 'role'), + name='tenancy_contactassignment_unique_object_contact_role' + ), + ), + ] diff --git a/netbox/tenancy/models/contacts.py b/netbox/tenancy/models/contacts.py index 1ea62db0c..e31330657 100644 --- a/netbox/tenancy/models/contacts.py +++ b/netbox/tenancy/models/contacts.py @@ -111,13 +111,13 @@ class Contact(PrimaryModel): class ContactAssignment(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel): - content_type = models.ForeignKey( + object_type = models.ForeignKey( to='contenttypes.ContentType', on_delete=models.CASCADE ) object_id = models.PositiveBigIntegerField() object = GenericForeignKey( - ct_field='content_type', + ct_field='object_type', fk_field='object_id' ) contact = models.ForeignKey( @@ -137,16 +137,16 @@ class ContactAssignment(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, Chan blank=True ) - clone_fields = ('content_type', 'object_id', 'role', 'priority') + clone_fields = ('object_type', 'object_id', 'role', 'priority') class Meta: ordering = ('contact', 'priority', 'role', 'pk') indexes = ( - models.Index(fields=('content_type', 'object_id')), + models.Index(fields=('object_type', 'object_id')), ) constraints = ( models.UniqueConstraint( - fields=('content_type', 'object_id', 'contact', 'role'), + fields=('object_type', 'object_id', 'contact', 'role'), name='%(app_label)s_%(class)s_unique_object_contact_role' ), ) @@ -165,9 +165,9 @@ class ContactAssignment(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, Chan super().clean() # Validate the assigned object type - if self.content_type not in ObjectType.objects.with_feature('contacts'): + if self.object_type not in ObjectType.objects.with_feature('contacts'): raise ValidationError( - _("Contacts cannot be assigned to this object type ({type}).").format(type=self.content_type) + _("Contacts cannot be assigned to this object type ({type}).").format(type=self.object_type) ) def to_objectchange(self, action): diff --git a/netbox/tenancy/tables/contacts.py b/netbox/tenancy/tables/contacts.py index a22c04569..946058218 100644 --- a/netbox/tenancy/tables/contacts.py +++ b/netbox/tenancy/tables/contacts.py @@ -86,7 +86,7 @@ class ContactTable(NetBoxTable): class ContactAssignmentTable(NetBoxTable): - content_type = columns.ContentTypeColumn( + object_type = columns.ContentTypeColumn( verbose_name=_('Object Type') ) object = tables.Column( @@ -141,10 +141,10 @@ class ContactAssignmentTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = ContactAssignment fields = ( - 'pk', 'content_type', 'object', 'contact', 'role', 'priority', 'contact_title', 'contact_phone', + 'pk', 'object_type', 'object', 'contact', 'role', 'priority', 'contact_title', 'contact_phone', 'contact_email', 'contact_address', 'contact_link', 'contact_description', 'contact_group', 'tags', 'actions' ) default_columns = ( - 'pk', 'content_type', 'object', 'contact', 'role', 'priority', 'contact_email', 'contact_phone' + 'pk', 'object_type', 'object', 'contact', 'role', 'priority', 'contact_email', 'contact_phone' ) diff --git a/netbox/tenancy/tests/test_api.py b/netbox/tenancy/tests/test_api.py index 175bfa947..de6b36fc6 100644 --- a/netbox/tenancy/tests/test_api.py +++ b/netbox/tenancy/tests/test_api.py @@ -246,21 +246,21 @@ class ContactAssignmentTest(APIViewTestCases.APIViewTestCase): cls.create_data = [ { - 'content_type': 'dcim.site', + 'object_type': 'dcim.site', 'object_id': sites[1].pk, 'contact': contacts[3].pk, 'role': contact_roles[0].pk, 'priority': ContactPriorityChoices.PRIORITY_PRIMARY, }, { - 'content_type': 'dcim.site', + 'object_type': 'dcim.site', 'object_id': sites[1].pk, 'contact': contacts[4].pk, 'role': contact_roles[1].pk, 'priority': ContactPriorityChoices.PRIORITY_SECONDARY, }, { - 'content_type': 'dcim.site', + 'object_type': 'dcim.site', 'object_id': sites[1].pk, 'contact': contacts[5].pk, 'role': contact_roles[2].pk, diff --git a/netbox/tenancy/tests/test_filtersets.py b/netbox/tenancy/tests/test_filtersets.py index ab72bd39f..729dd7204 100644 --- a/netbox/tenancy/tests/test_filtersets.py +++ b/netbox/tenancy/tests/test_filtersets.py @@ -295,8 +295,8 @@ class ContactAssignmentTestCase(TestCase, ChangeLoggedFilterSetTests): ) ContactAssignment.objects.bulk_create(assignments) - def test_content_type(self): - params = {'content_type_id': ContentType.objects.get_by_natural_key('dcim', 'site')} + def test_object_type(self): + params = {'object_type_id': ContentType.objects.get_by_natural_key('dcim', 'site')} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) def test_contact(self): diff --git a/netbox/tenancy/tests/test_views.py b/netbox/tenancy/tests/test_views.py index 2151a6e8b..cbdecc0d0 100644 --- a/netbox/tenancy/tests/test_views.py +++ b/netbox/tenancy/tests/test_views.py @@ -292,7 +292,7 @@ class ContactAssignmentTestCase( tags = create_tags('Alpha', 'Bravo', 'Charlie') cls.form_data = { - 'content_type': ContentType.objects.get_for_model(Site).pk, + 'object_type': ContentType.objects.get_for_model(Site).pk, 'object_id': sites[3].pk, 'contact': contacts[3].pk, 'role': contact_roles[3].pk, @@ -306,11 +306,11 @@ class ContactAssignmentTestCase( } def _get_url(self, action, instance=None): - # Override creation URL to append content_type & object_id parameters + # Override creation URL to append object_type & object_id parameters if action == 'add': url = reverse('tenancy:contactassignment_add') content_type = ContentType.objects.get_for_model(Site).pk object_id = Site.objects.first().pk - return f"{url}?content_type={content_type}&object_id={object_id}" + return f"{url}?object_type={content_type}&object_id={object_id}" return super()._get_url(action, instance=instance) diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 1d2fceb04..4c4d263df 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -23,7 +23,7 @@ class ObjectContactsView(generic.ObjectChildrenView): def get_children(self, request, parent): return ContactAssignment.objects.restrict(request.user, 'view').filter( - content_type=ContentType.objects.get_for_model(parent), + object_type=ContentType.objects.get_for_model(parent), object_id=parent.pk ).order_by('priority', 'contact', 'role') @@ -31,7 +31,7 @@ class ObjectContactsView(generic.ObjectChildrenView): table = super().get_table(*args, **kwargs) # Hide object columns - table.columns.hide('content_type') + table.columns.hide('object_type') table.columns.hide('object') return table @@ -374,8 +374,8 @@ class ContactAssignmentEditView(generic.ObjectEditView): def alter_object(self, instance, request, args, kwargs): if not instance.pk: # Assign the object based on URL kwargs - content_type = get_object_or_404(ContentType, pk=request.GET.get('content_type')) - instance.object = get_object_or_404(content_type.model_class(), pk=request.GET.get('object_id')) + object_type = get_object_or_404(ContentType, pk=request.GET.get('object_type')) + instance.object = get_object_or_404(object_type.model_class(), pk=request.GET.get('object_id')) return instance def get_extra_addanother_params(self, request):