Rename ExportTemplate.content_types to object_types & use ObjectType proxy

This commit is contained in:
Jeremy Stretch 2024-03-01 15:54:21 -05:00
parent e51d71d7e6
commit bef17e5a95
15 changed files with 54 additions and 41 deletions

View File

@ -216,7 +216,7 @@ class CustomLinkSerializer(ValidatedModelSerializer):
class ExportTemplateSerializer(ValidatedModelSerializer): class ExportTemplateSerializer(ValidatedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='extras-api:exporttemplate-detail') url = serializers.HyperlinkedIdentityField(view_name='extras-api:exporttemplate-detail')
content_types = ContentTypeField( object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('export_templates'), queryset=ObjectType.objects.with_feature('export_templates'),
many=True many=True
) )
@ -230,7 +230,7 @@ class ExportTemplateSerializer(ValidatedModelSerializer):
class Meta: class Meta:
model = ExportTemplate model = ExportTemplate
fields = [ fields = [
'id', 'url', 'display', 'content_types', 'name', 'description', 'template_code', 'mime_type', 'id', 'url', 'display', 'object_types', 'name', 'description', 'template_code', 'mime_type',
'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file', 'data_synced', 'created', 'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file', 'data_synced', 'created',
'last_updated', 'last_updated',
] ]

View File

@ -217,10 +217,10 @@ class ExportTemplateFilterSet(BaseFilterSet):
method='search', method='search',
label=_('Search'), label=_('Search'),
) )
content_type_id = MultiValueNumberFilter( object_types_id = MultiValueNumberFilter(
field_name='content_types__id' field_name='object_types__id'
) )
content_types = ContentTypeFilter() object_types = ContentTypeFilter()
data_source_id = django_filters.ModelMultipleChoiceFilter( data_source_id = django_filters.ModelMultipleChoiceFilter(
queryset=DataSource.objects.all(), queryset=DataSource.objects.all(),
label=_('Data source (ID)'), label=_('Data source (ID)'),
@ -232,7 +232,7 @@ class ExportTemplateFilterSet(BaseFilterSet):
class Meta: class Meta:
model = ExportTemplate model = ExportTemplate
fields = ['id', 'content_types', 'name', 'description', 'data_synced'] fields = ['id', 'object_types', 'name', 'description', 'data_synced']
def search(self, queryset, name, value): def search(self, queryset, name, value):
if not value.strip(): if not value.strip():

View File

@ -126,8 +126,8 @@ class CustomLinkImportForm(CSVModelForm):
class ExportTemplateImportForm(CSVModelForm): class ExportTemplateImportForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( object_types = CSVMultipleContentTypeField(
label=_('Content types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('export_templates'), queryset=ObjectType.objects.with_feature('export_templates'),
help_text=_("One or more assigned object types") help_text=_("One or more assigned object types")
) )
@ -135,7 +135,7 @@ class ExportTemplateImportForm(CSVModelForm):
class Meta: class Meta:
model = ExportTemplate model = ExportTemplate
fields = ( fields = (
'name', 'content_types', 'description', 'mime_type', 'file_extension', 'as_attachment', 'template_code', 'name', 'object_types', 'description', 'mime_type', 'file_extension', 'as_attachment', 'template_code',
) )

View File

@ -139,7 +139,7 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id')), (None, ('q', 'filter_id')),
(_('Data'), ('data_source_id', 'data_file_id')), (_('Data'), ('data_source_id', 'data_file_id')),
(_('Attributes'), ('content_type_id', 'mime_type', 'file_extension', 'as_attachment')), (_('Attributes'), ('object_types_id', 'mime_type', 'file_extension', 'as_attachment')),
) )
data_source_id = DynamicModelMultipleChoiceField( data_source_id = DynamicModelMultipleChoiceField(
queryset=DataSource.objects.all(), queryset=DataSource.objects.all(),
@ -154,7 +154,7 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
'source_id': '$data_source_id' 'source_id': '$data_source_id'
} }
) )
content_type_id = ContentTypeMultipleChoiceField( object_types_id = ContentTypeMultipleChoiceField(
queryset=ObjectType.objects.with_feature('export_templates'), queryset=ObjectType.objects.with_feature('export_templates'),
required=False, required=False,
label=_('Content types') label=_('Content types')

View File

@ -151,8 +151,8 @@ class CustomLinkForm(forms.ModelForm):
class ExportTemplateForm(SyncedDataMixin, forms.ModelForm): class ExportTemplateForm(SyncedDataMixin, forms.ModelForm):
content_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Content types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('export_templates') queryset=ObjectType.objects.with_feature('export_templates')
) )
template_code = forms.CharField( template_code = forms.CharField(
@ -162,7 +162,7 @@ class ExportTemplateForm(SyncedDataMixin, forms.ModelForm):
) )
fieldsets = ( fieldsets = (
(_('Export Template'), ('name', 'content_types', 'description', 'template_code')), (_('Export Template'), ('name', 'object_types', 'description', 'template_code')),
(_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')), (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')),
(_('Rendering'), ('mime_type', 'file_extension', 'as_attachment')), (_('Rendering'), ('mime_type', 'file_extension', 'as_attachment')),
) )

View File

@ -71,7 +71,7 @@ class ExportTemplateType(ObjectType):
class Meta: class Meta:
model = models.ExportTemplate model = models.ExportTemplate
exclude = ('content_types', ) exclude = ('object_types', )
filterset_class = filtersets.ExportTemplateFilterSet filterset_class = filtersets.ExportTemplateFilterSet

View File

@ -50,4 +50,16 @@ class Migration(migrations.Migration):
name='object_types', name='object_types',
field=models.ManyToManyField(related_name='event_rules', to='core.objecttype'), field=models.ManyToManyField(related_name='event_rules', to='core.objecttype'),
), ),
# Export templates
migrations.RenameField(
model_name='exporttemplate',
old_name='content_types',
new_name='object_types',
),
migrations.AlterField(
model_name='exporttemplate',
name='object_types',
field=models.ManyToManyField(related_name='export_templates', to='core.objecttype'),
),
] ]

View File

@ -409,8 +409,8 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
content_types = models.ManyToManyField( object_types = models.ManyToManyField(
to='contenttypes.ContentType', to='core.ObjectType',
related_name='export_templates', related_name='export_templates',
help_text=_('The object type(s) to which this template applies.') help_text=_('The object type(s) to which this template applies.')
) )

View File

@ -139,8 +139,8 @@ class ExportTemplateTable(NetBoxTable):
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
) )
content_types = columns.ContentTypesColumn( object_types = columns.ContentTypesColumn(
verbose_name=_('Content Types'), verbose_name=_('Object Types'),
) )
as_attachment = columns.BooleanColumn( as_attachment = columns.BooleanColumn(
verbose_name=_('As Attachment'), verbose_name=_('As Attachment'),
@ -161,11 +161,11 @@ class ExportTemplateTable(NetBoxTable):
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = ExportTemplate model = ExportTemplate
fields = ( fields = (
'pk', 'id', 'name', 'content_types', 'description', 'mime_type', 'file_extension', 'as_attachment', 'pk', 'id', 'name', 'object_types', 'description', 'mime_type', 'file_extension', 'as_attachment',
'data_source', 'data_file', 'data_synced', 'created', 'last_updated', 'data_source', 'data_file', 'data_synced', 'created', 'last_updated',
) )
default_columns = ( default_columns = (
'pk', 'name', 'content_types', 'description', 'mime_type', 'file_extension', 'as_attachment', 'is_synced', 'pk', 'name', 'object_types', 'description', 'mime_type', 'file_extension', 'as_attachment', 'is_synced',
) )

View File

@ -458,17 +458,17 @@ class ExportTemplateTest(APIViewTestCases.APIViewTestCase):
brief_fields = ['description', 'display', 'id', 'name', 'url'] brief_fields = ['description', 'display', 'id', 'name', 'url']
create_data = [ create_data = [
{ {
'content_types': ['dcim.device'], 'object_types': ['dcim.device'],
'name': 'Test Export Template 4', 'name': 'Test Export Template 4',
'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}', 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
}, },
{ {
'content_types': ['dcim.device'], 'object_types': ['dcim.device'],
'name': 'Test Export Template 5', 'name': 'Test Export Template 5',
'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}', 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
}, },
{ {
'content_types': ['dcim.device'], 'object_types': ['dcim.device'],
'name': 'Test Export Template 6', 'name': 'Test Export Template 6',
'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}', 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
}, },
@ -495,7 +495,7 @@ class ExportTemplateTest(APIViewTestCases.APIViewTestCase):
) )
ExportTemplate.objects.bulk_create(export_templates) ExportTemplate.objects.bulk_create(export_templates)
for et in export_templates: for et in export_templates:
et.content_types.set([ContentType.objects.get_for_model(Device)]) et.object_types.set([ObjectType.objects.get_for_model(Device)])
class TagTest(APIViewTestCases.APIViewTestCase): class TagTest(APIViewTestCases.APIViewTestCase):

View File

@ -639,7 +639,7 @@ class ExportTemplateTestCase(TestCase, BaseFilterSetTests):
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
content_types = ContentType.objects.filter(model__in=['site', 'rack', 'device']) object_types = ObjectType.objects.filter(model__in=['site', 'rack', 'device'])
export_templates = ( export_templates = (
ExportTemplate(name='Export Template 1', template_code='TESTING', description='foobar1'), ExportTemplate(name='Export Template 1', template_code='TESTING', description='foobar1'),
@ -648,7 +648,7 @@ class ExportTemplateTestCase(TestCase, BaseFilterSetTests):
) )
ExportTemplate.objects.bulk_create(export_templates) ExportTemplate.objects.bulk_create(export_templates)
for i, et in enumerate(export_templates): for i, et in enumerate(export_templates):
et.content_types.set([content_types[i]]) et.object_types.set([object_types[i]])
def test_q(self): def test_q(self):
params = {'q': 'foobar1'} params = {'q': 'foobar1'}
@ -658,10 +658,10 @@ class ExportTemplateTestCase(TestCase, BaseFilterSetTests):
params = {'name': ['Export Template 1', 'Export Template 2']} params = {'name': ['Export Template 1', 'Export Template 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_content_types(self): def test_object_types(self):
params = {'content_types': 'dcim.site'} params = {'object_types': 'dcim.site'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
params = {'content_type_id': [ContentType.objects.get_for_model(Site).pk]} params = {'object_types_id': [ContentType.objects.get_for_model(Site).pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_description(self): def test_description(self):

View File

@ -303,7 +303,7 @@ class ExportTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
site_ct = ContentType.objects.get_for_model(Site) site_type = ObjectType.objects.get_for_model(Site)
TEMPLATE_CODE = """{% for object in queryset %}{{ object }}{% endfor %}""" TEMPLATE_CODE = """{% for object in queryset %}{{ object }}{% endfor %}"""
export_templates = ( export_templates = (
@ -313,16 +313,16 @@ class ExportTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
) )
ExportTemplate.objects.bulk_create(export_templates) ExportTemplate.objects.bulk_create(export_templates)
for et in export_templates: for et in export_templates:
et.content_types.set([site_ct]) et.object_types.set([site_type])
cls.form_data = { cls.form_data = {
'name': 'Export Template X', 'name': 'Export Template X',
'content_types': [site_ct.pk], 'object_types': [site_type.pk],
'template_code': TEMPLATE_CODE, 'template_code': TEMPLATE_CODE,
} }
cls.csv_data = ( cls.csv_data = (
"name,content_types,template_code", "name,object_types,template_code",
f"Export Template 4,dcim.site,{TEMPLATE_CODE}", f"Export Template 4,dcim.site,{TEMPLATE_CODE}",
f"Export Template 5,dcim.site,{TEMPLATE_CODE}", f"Export Template 5,dcim.site,{TEMPLATE_CODE}",
f"Export Template 6,dcim.site,{TEMPLATE_CODE}", f"Export Template 6,dcim.site,{TEMPLATE_CODE}",

View File

@ -70,9 +70,9 @@
<div class="card"> <div class="card">
<h5 class="card-header">{% trans "Assigned Models" %}</h5> <h5 class="card-header">{% trans "Assigned Models" %}</h5>
<table class="table table-hover attr-table"> <table class="table table-hover attr-table">
{% for ct in object.content_types.all %} {% for object_type in object.object_types.all %}
<tr> <tr>
<td>{{ ct }}</td> <td>{{ object_type }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

View File

@ -25,7 +25,7 @@
<hr class="dropdown-divider"> <hr class="dropdown-divider">
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'extras:exporttemplate_add' %}?content_types={{ content_type.pk }}">{% trans "Add export template" %}...</a> <a class="dropdown-item" href="{% url 'extras:exporttemplate_add' %}?object_types={{ object_type.pk }}">{% trans "Add export template" %}...</a>
</li> </li>
{% endif %} {% endif %}
</ul> </ul>

View File

@ -2,6 +2,7 @@ from django import template
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.urls import NoReverseMatch, reverse from django.urls import NoReverseMatch, reverse
from core.models import ObjectType
from extras.models import Bookmark, ExportTemplate from extras.models import Bookmark, ExportTemplate
from utilities.utils import get_viewname, prepare_cloned_fields from utilities.utils import get_viewname, prepare_cloned_fields
@ -132,18 +133,18 @@ def import_button(model, action='import'):
@register.inclusion_tag('buttons/export.html', takes_context=True) @register.inclusion_tag('buttons/export.html', takes_context=True)
def export_button(context, model): def export_button(context, model):
content_type = ContentType.objects.get_for_model(model) object_type = ObjectType.objects.get_for_model(model)
user = context['request'].user user = context['request'].user
# Determine if the "all data" export returns CSV or YAML # Determine if the "all data" export returns CSV or YAML
data_format = 'YAML' if hasattr(content_type.model_class(), 'to_yaml') else 'CSV' data_format = 'YAML' if hasattr(object_type.model_class(), 'to_yaml') else 'CSV'
# Retrieve all export templates for this model # Retrieve all export templates for this model
export_templates = ExportTemplate.objects.restrict(user, 'view').filter(content_types=content_type) export_templates = ExportTemplate.objects.restrict(user, 'view').filter(object_types=object_type)
return { return {
'perms': context['perms'], 'perms': context['perms'],
'content_type': content_type, 'object_type': object_type,
'url_params': context['request'].GET.urlencode() if context['request'].GET else '', 'url_params': context['request'].GET.urlencode() if context['request'].GET else '',
'export_templates': export_templates, 'export_templates': export_templates,
'data_format': data_format, 'data_format': data_format,