mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
#4711: Rename CustomField.obj_type to content_types
This commit is contained in:
@ -79,7 +79,7 @@ class CustomFieldForm(forms.ModelForm):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
order_content_types(self.fields['obj_type'])
|
order_content_types(self.fields['content_types'])
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ class CustomFieldAdmin(admin.ModelAdmin):
|
|||||||
'name', 'models', 'type', 'required', 'filter_logic', 'default', 'weight', 'description',
|
'name', 'models', 'type', 'required', 'filter_logic', 'default', 'weight', 'description',
|
||||||
]
|
]
|
||||||
list_filter = [
|
list_filter = [
|
||||||
'type', 'required', 'obj_type',
|
'type', 'required', 'content_types',
|
||||||
]
|
]
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Custom Field', {
|
('Custom Field', {
|
||||||
@ -106,7 +106,7 @@ class CustomFieldAdmin(admin.ModelAdmin):
|
|||||||
}),
|
}),
|
||||||
('Assignment', {
|
('Assignment', {
|
||||||
'description': 'A custom field must be assigned to one or more object types.',
|
'description': 'A custom field must be assigned to one or more object types.',
|
||||||
'fields': ('obj_type',)
|
'fields': ('content_types',)
|
||||||
}),
|
}),
|
||||||
('Choices', {
|
('Choices', {
|
||||||
'description': 'A selection field must have two or more choices assigned to it.',
|
'description': 'A selection field must have two or more choices assigned to it.',
|
||||||
@ -115,7 +115,7 @@ class CustomFieldAdmin(admin.ModelAdmin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def models(self, obj):
|
def models(self, obj):
|
||||||
return ', '.join([ct.name for ct in obj.obj_type.all()])
|
return ', '.join([ct.name for ct in obj.content_types.all()])
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -24,7 +24,7 @@ class CustomFieldDefaultValues:
|
|||||||
|
|
||||||
# Retrieve the CustomFields for the parent model
|
# Retrieve the CustomFields for the parent model
|
||||||
content_type = ContentType.objects.get_for_model(self.model)
|
content_type = ContentType.objects.get_for_model(self.model)
|
||||||
fields = CustomField.objects.filter(obj_type=content_type)
|
fields = CustomField.objects.filter(content_types=content_type)
|
||||||
|
|
||||||
# Populate the default value for each CustomField
|
# Populate the default value for each CustomField
|
||||||
value = {}
|
value = {}
|
||||||
@ -52,7 +52,7 @@ class CustomFieldsDataField(Field):
|
|||||||
"""
|
"""
|
||||||
if not hasattr(self, '_custom_fields'):
|
if not hasattr(self, '_custom_fields'):
|
||||||
content_type = ContentType.objects.get_for_model(self.parent.Meta.model)
|
content_type = ContentType.objects.get_for_model(self.parent.Meta.model)
|
||||||
self._custom_fields = CustomField.objects.filter(obj_type=content_type)
|
self._custom_fields = CustomField.objects.filter(content_types=content_type)
|
||||||
return self._custom_fields
|
return self._custom_fields
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@ -132,7 +132,7 @@ class CustomFieldModelSerializer(ValidatedModelSerializer):
|
|||||||
|
|
||||||
# Retrieve the set of CustomFields which apply to this type of object
|
# Retrieve the set of CustomFields which apply to this type of object
|
||||||
content_type = ContentType.objects.get_for_model(self.Meta.model)
|
content_type = ContentType.objects.get_for_model(self.Meta.model)
|
||||||
fields = CustomField.objects.filter(obj_type=content_type)
|
fields = CustomField.objects.filter(content_types=content_type)
|
||||||
|
|
||||||
# Populate CustomFieldValues for each instance from database
|
# Populate CustomFieldValues for each instance from database
|
||||||
if type(self.instance) in (list, tuple):
|
if type(self.instance) in (list, tuple):
|
||||||
|
@ -65,9 +65,8 @@ class CustomFieldFilterSet(django_filters.FilterSet):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
obj_type = ContentType.objects.get_for_model(self._meta.model)
|
|
||||||
custom_fields = CustomField.objects.filter(
|
custom_fields = CustomField.objects.filter(
|
||||||
obj_type=obj_type
|
content_types=ContentType.objects.get_for_model(self._meta.model)
|
||||||
).exclude(
|
).exclude(
|
||||||
filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED
|
filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED
|
||||||
)
|
)
|
||||||
|
@ -35,7 +35,7 @@ class CustomFieldModelForm(forms.ModelForm):
|
|||||||
Append form fields for all CustomFields assigned to this model.
|
Append form fields for all CustomFields assigned to this model.
|
||||||
"""
|
"""
|
||||||
# Append form fields; assign initial values if modifying and existing object
|
# Append form fields; assign initial values if modifying and existing object
|
||||||
for cf in CustomField.objects.filter(obj_type=self.obj_type):
|
for cf in CustomField.objects.filter(content_types=self.obj_type):
|
||||||
field_name = 'cf_{}'.format(cf.name)
|
field_name = 'cf_{}'.format(cf.name)
|
||||||
if self.instance.pk:
|
if self.instance.pk:
|
||||||
self.fields[field_name] = cf.to_form_field(set_initial=False)
|
self.fields[field_name] = cf.to_form_field(set_initial=False)
|
||||||
@ -60,7 +60,7 @@ class CustomFieldModelCSVForm(CSVModelForm, CustomFieldModelForm):
|
|||||||
def _append_customfield_fields(self):
|
def _append_customfield_fields(self):
|
||||||
|
|
||||||
# Append form fields
|
# Append form fields
|
||||||
for cf in CustomField.objects.filter(obj_type=self.obj_type):
|
for cf in CustomField.objects.filter(content_types=self.obj_type):
|
||||||
field_name = 'cf_{}'.format(cf.name)
|
field_name = 'cf_{}'.format(cf.name)
|
||||||
self.fields[field_name] = cf.to_form_field(for_csv_import=True)
|
self.fields[field_name] = cf.to_form_field(for_csv_import=True)
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ class CustomFieldBulkEditForm(BulkEditForm):
|
|||||||
self.obj_type = ContentType.objects.get_for_model(self.model)
|
self.obj_type = ContentType.objects.get_for_model(self.model)
|
||||||
|
|
||||||
# Add all applicable CustomFields to the form
|
# Add all applicable CustomFields to the form
|
||||||
custom_fields = CustomField.objects.filter(obj_type=self.obj_type)
|
custom_fields = CustomField.objects.filter(content_types=self.obj_type)
|
||||||
for cf in custom_fields:
|
for cf in custom_fields:
|
||||||
# Annotate non-required custom fields as nullable
|
# Annotate non-required custom fields as nullable
|
||||||
if not cf.required:
|
if not cf.required:
|
||||||
@ -96,7 +96,7 @@ class CustomFieldFilterForm(forms.Form):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Add all applicable CustomFields to the form
|
# Add all applicable CustomFields to the form
|
||||||
custom_fields = CustomField.objects.filter(obj_type=self.obj_type).exclude(
|
custom_fields = CustomField.objects.filter(content_types=self.obj_type).exclude(
|
||||||
filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED
|
filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED
|
||||||
)
|
)
|
||||||
for cf in custom_fields:
|
for cf in custom_fields:
|
||||||
|
@ -32,4 +32,10 @@ class Migration(migrations.Migration):
|
|||||||
size=None
|
size=None
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
# Rename obj_type to content_types
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='customfield',
|
||||||
|
old_name='obj_type',
|
||||||
|
new_name='content_types',
|
||||||
|
),
|
||||||
]
|
]
|
@ -56,7 +56,7 @@ class Migration(migrations.Migration):
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
('circuits', '0020_custom_field_data'),
|
('circuits', '0020_custom_field_data'),
|
||||||
('dcim', '0117_custom_field_data'),
|
('dcim', '0117_custom_field_data'),
|
||||||
('extras', '0050_customfield_add_choices'),
|
('extras', '0050_customfield_changes'),
|
||||||
('ipam', '0038_custom_field_data'),
|
('ipam', '0038_custom_field_data'),
|
||||||
('secrets', '0010_custom_field_data'),
|
('secrets', '0010_custom_field_data'),
|
||||||
('tenancy', '0010_custom_field_data'),
|
('tenancy', '0010_custom_field_data'),
|
||||||
|
@ -50,11 +50,11 @@ class CustomFieldManager(models.Manager):
|
|||||||
Return all CustomFields assigned to the given model.
|
Return all CustomFields assigned to the given model.
|
||||||
"""
|
"""
|
||||||
content_type = ContentType.objects.get_for_model(model._meta.concrete_model)
|
content_type = ContentType.objects.get_for_model(model._meta.concrete_model)
|
||||||
return self.get_queryset().filter(obj_type=content_type)
|
return self.get_queryset().filter(content_types=content_type)
|
||||||
|
|
||||||
|
|
||||||
class CustomField(models.Model):
|
class CustomField(models.Model):
|
||||||
obj_type = models.ManyToManyField(
|
content_types = models.ManyToManyField(
|
||||||
to=ContentType,
|
to=ContentType,
|
||||||
related_name='custom_fields',
|
related_name='custom_fields',
|
||||||
verbose_name='Object(s)',
|
verbose_name='Object(s)',
|
||||||
|
@ -8,7 +8,6 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.core.validators import ValidationError
|
from django.core.validators import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.template import Template, Context
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from rest_framework.utils.encoders import JSONEncoder
|
from rest_framework.utils.encoders import JSONEncoder
|
||||||
@ -32,6 +31,7 @@ class Webhook(models.Model):
|
|||||||
delete in NetBox. The request will contain a representation of the object, which the remote application can act on.
|
delete in NetBox. The request will contain a representation of the object, which the remote application can act on.
|
||||||
Each Webhook can be limited to firing only on certain actions or certain object types.
|
Each Webhook can be limited to firing only on certain actions or certain object types.
|
||||||
"""
|
"""
|
||||||
|
# TODO: Rename obj_type to content_types (see #4711)
|
||||||
obj_type = models.ManyToManyField(
|
obj_type = models.ManyToManyField(
|
||||||
to=ContentType,
|
to=ContentType,
|
||||||
related_name='webhooks',
|
related_name='webhooks',
|
||||||
|
@ -89,10 +89,10 @@ def handle_cf_deleted(instance, **kwargs):
|
|||||||
"""
|
"""
|
||||||
Handle the cleanup of old custom field data when a CustomField is deleted.
|
Handle the cleanup of old custom field data when a CustomField is deleted.
|
||||||
"""
|
"""
|
||||||
instance.remove_stale_data(instance.obj_type.all())
|
instance.remove_stale_data(instance.content_types.all())
|
||||||
|
|
||||||
|
|
||||||
m2m_changed.connect(handle_cf_removed_obj_types, sender=CustomField.obj_type.through)
|
m2m_changed.connect(handle_cf_removed_obj_types, sender=CustomField.content_types.through)
|
||||||
pre_delete.connect(handle_cf_deleted, sender=CustomField)
|
pre_delete.connect(handle_cf_deleted, sender=CustomField)
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class ChangeLogViewTest(ModelViewTestCase):
|
|||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
cf.save()
|
cf.save()
|
||||||
cf.obj_type.set([ct])
|
cf.content_types.set([ct])
|
||||||
|
|
||||||
def test_create_object(self):
|
def test_create_object(self):
|
||||||
tags = self.create_tags('Tag 1', 'Tag 2')
|
tags = self.create_tags('Tag 1', 'Tag 2')
|
||||||
@ -131,7 +131,7 @@ class ChangeLogAPITest(APITestCase):
|
|||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
cf.save()
|
cf.save()
|
||||||
cf.obj_type.set([ct])
|
cf.content_types.set([ct])
|
||||||
|
|
||||||
# Create some tags
|
# Create some tags
|
||||||
tags = (
|
tags = (
|
||||||
|
@ -39,7 +39,7 @@ class CustomFieldTest(TestCase):
|
|||||||
# Create a custom field
|
# Create a custom field
|
||||||
cf = CustomField(type=data['field_type'], name='my_field', required=False)
|
cf = CustomField(type=data['field_type'], name='my_field', required=False)
|
||||||
cf.save()
|
cf.save()
|
||||||
cf.obj_type.set([obj_type])
|
cf.content_types.set([obj_type])
|
||||||
cf.save()
|
cf.save()
|
||||||
|
|
||||||
# Assign a value to the first Site
|
# Assign a value to the first Site
|
||||||
@ -72,7 +72,7 @@ class CustomFieldTest(TestCase):
|
|||||||
choices=['Option A', 'Option B', 'Option C']
|
choices=['Option A', 'Option B', 'Option C']
|
||||||
)
|
)
|
||||||
cf.save()
|
cf.save()
|
||||||
cf.obj_type.set([obj_type])
|
cf.content_types.set([obj_type])
|
||||||
cf.save()
|
cf.save()
|
||||||
|
|
||||||
# Assign a value to the first Site
|
# Assign a value to the first Site
|
||||||
@ -100,7 +100,7 @@ class CustomFieldManagerTest(TestCase):
|
|||||||
content_type = ContentType.objects.get_for_model(Site)
|
content_type = ContentType.objects.get_for_model(Site)
|
||||||
custom_field = CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='text_field', default='foo')
|
custom_field = CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='text_field', default='foo')
|
||||||
custom_field.save()
|
custom_field.save()
|
||||||
custom_field.obj_type.set([content_type])
|
custom_field.content_types.set([content_type])
|
||||||
|
|
||||||
def test_get_for_model(self):
|
def test_get_for_model(self):
|
||||||
self.assertEqual(CustomField.objects.get_for_model(Site).count(), 1)
|
self.assertEqual(CustomField.objects.get_for_model(Site).count(), 1)
|
||||||
@ -116,33 +116,33 @@ class CustomFieldAPITest(APITestCase):
|
|||||||
# Text custom field
|
# Text custom field
|
||||||
cls.cf_text = CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='text_field', default='foo')
|
cls.cf_text = CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='text_field', default='foo')
|
||||||
cls.cf_text.save()
|
cls.cf_text.save()
|
||||||
cls.cf_text.obj_type.set([content_type])
|
cls.cf_text.content_types.set([content_type])
|
||||||
|
|
||||||
# Integer custom field
|
# Integer custom field
|
||||||
cls.cf_integer = CustomField(type=CustomFieldTypeChoices.TYPE_INTEGER, name='number_field', default=123)
|
cls.cf_integer = CustomField(type=CustomFieldTypeChoices.TYPE_INTEGER, name='number_field', default=123)
|
||||||
cls.cf_integer.save()
|
cls.cf_integer.save()
|
||||||
cls.cf_integer.obj_type.set([content_type])
|
cls.cf_integer.content_types.set([content_type])
|
||||||
|
|
||||||
# Boolean custom field
|
# Boolean custom field
|
||||||
cls.cf_boolean = CustomField(type=CustomFieldTypeChoices.TYPE_BOOLEAN, name='boolean_field', default=False)
|
cls.cf_boolean = CustomField(type=CustomFieldTypeChoices.TYPE_BOOLEAN, name='boolean_field', default=False)
|
||||||
cls.cf_boolean.save()
|
cls.cf_boolean.save()
|
||||||
cls.cf_boolean.obj_type.set([content_type])
|
cls.cf_boolean.content_types.set([content_type])
|
||||||
|
|
||||||
# Date custom field
|
# Date custom field
|
||||||
cls.cf_date = CustomField(type=CustomFieldTypeChoices.TYPE_DATE, name='date_field', default='2020-01-01')
|
cls.cf_date = CustomField(type=CustomFieldTypeChoices.TYPE_DATE, name='date_field', default='2020-01-01')
|
||||||
cls.cf_date.save()
|
cls.cf_date.save()
|
||||||
cls.cf_date.obj_type.set([content_type])
|
cls.cf_date.content_types.set([content_type])
|
||||||
|
|
||||||
# URL custom field
|
# URL custom field
|
||||||
cls.cf_url = CustomField(type=CustomFieldTypeChoices.TYPE_URL, name='url_field', default='http://example.com/1')
|
cls.cf_url = CustomField(type=CustomFieldTypeChoices.TYPE_URL, name='url_field', default='http://example.com/1')
|
||||||
cls.cf_url.save()
|
cls.cf_url.save()
|
||||||
cls.cf_url.obj_type.set([content_type])
|
cls.cf_url.content_types.set([content_type])
|
||||||
|
|
||||||
# Select custom field
|
# Select custom field
|
||||||
cls.cf_select = CustomField(type=CustomFieldTypeChoices.TYPE_SELECT, name='choice_field', choices=['Foo', 'Bar', 'Baz'])
|
cls.cf_select = CustomField(type=CustomFieldTypeChoices.TYPE_SELECT, name='choice_field', choices=['Foo', 'Bar', 'Baz'])
|
||||||
cls.cf_select.default = 'Foo'
|
cls.cf_select.default = 'Foo'
|
||||||
cls.cf_select.save()
|
cls.cf_select.save()
|
||||||
cls.cf_select.obj_type.set([content_type])
|
cls.cf_select.content_types.set([content_type])
|
||||||
|
|
||||||
# Create some sites
|
# Create some sites
|
||||||
cls.sites = (
|
cls.sites = (
|
||||||
@ -429,7 +429,7 @@ class CustomFieldImportTest(TestCase):
|
|||||||
)
|
)
|
||||||
for cf in custom_fields:
|
for cf in custom_fields:
|
||||||
cf.save()
|
cf.save()
|
||||||
cf.obj_type.set([ContentType.objects.get_for_model(Site)])
|
cf.content_types.set([ContentType.objects.get_for_model(Site)])
|
||||||
|
|
||||||
def test_import(self):
|
def test_import(self):
|
||||||
"""
|
"""
|
||||||
|
@ -131,7 +131,7 @@ class APIDocsTestCase(TestCase):
|
|||||||
content_type = ContentType.objects.get_for_model(Site)
|
content_type = ContentType.objects.get_for_model(Site)
|
||||||
self.cf_text = CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='test')
|
self.cf_text = CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='test')
|
||||||
self.cf_text.save()
|
self.cf_text.save()
|
||||||
self.cf_text.obj_type.set([content_type])
|
self.cf_text.content_types.set([content_type])
|
||||||
self.cf_text.save()
|
self.cf_text.save()
|
||||||
|
|
||||||
def test_api_docs(self):
|
def test_api_docs(self):
|
||||||
|
Reference in New Issue
Block a user