mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 04:22:01 -06:00
Standardize add, import, and export functionality for tags
This commit is contained in:
parent
057a022205
commit
da906f48d9
@ -1,6 +1,7 @@
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.safestring import mark_safe
|
||||
from mptt.forms import TreeNodeMultipleChoiceField
|
||||
from taggit.forms import TagField as TagField_
|
||||
|
||||
@ -161,6 +162,17 @@ class TagForm(BootstrapMixin, forms.ModelForm):
|
||||
]
|
||||
|
||||
|
||||
class TagCSVForm(CSVModelForm):
|
||||
slug = SlugField()
|
||||
|
||||
class Meta:
|
||||
model = Tag
|
||||
fields = Tag.csv_headers
|
||||
help_texts = {
|
||||
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'),
|
||||
}
|
||||
|
||||
|
||||
class AddRemoveTagsForm(forms.Form):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -24,6 +24,8 @@ class Tag(TagBase, ChangeLoggedModel):
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
|
||||
csv_headers = ['name', 'slug', 'color', 'description']
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('extras:tag', args=[self.slug])
|
||||
|
||||
@ -34,6 +36,14 @@ class Tag(TagBase, ChangeLoggedModel):
|
||||
slug += "_%d" % i
|
||||
return slug
|
||||
|
||||
def to_csv(self):
|
||||
return (
|
||||
self.name,
|
||||
self.slug,
|
||||
self.color,
|
||||
self.description
|
||||
)
|
||||
|
||||
|
||||
class TaggedItem(GenericTaggedItemBase):
|
||||
tag = models.ForeignKey(
|
||||
|
@ -10,16 +10,7 @@ from extras.models import ConfigContext, ObjectChange, Tag
|
||||
from utilities.testing import ViewTestCases, TestCase
|
||||
|
||||
|
||||
# TODO: Change base class to PrimaryObjectViewTestCase
|
||||
# Blocked by #3703
|
||||
class TagTestCase(
|
||||
ViewTestCases.GetObjectViewTestCase,
|
||||
ViewTestCases.EditObjectViewTestCase,
|
||||
ViewTestCases.DeleteObjectViewTestCase,
|
||||
ViewTestCases.ListObjectsViewTestCase,
|
||||
ViewTestCases.BulkEditObjectsViewTestCase,
|
||||
ViewTestCases.BulkDeleteObjectsViewTestCase
|
||||
):
|
||||
class TagTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
model = Tag
|
||||
|
||||
@classmethod
|
||||
@ -38,6 +29,13 @@ class TagTestCase(
|
||||
'comments': 'Some comments',
|
||||
}
|
||||
|
||||
cls.csv_data = (
|
||||
"name,slug,color,description",
|
||||
"Tag 4,tag-4,ff0000,Fourth tag",
|
||||
"Tag 5,tag-5,00ff00,Fifth tag",
|
||||
"Tag 6,tag-6,0000ff,Sixth tag",
|
||||
)
|
||||
|
||||
cls.bulk_edit_data = {
|
||||
'color': '00ff00',
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ urlpatterns = [
|
||||
|
||||
# Tags
|
||||
path('tags/', views.TagListView.as_view(), name='tag_list'),
|
||||
path('tags/add/', views.TagEditView.as_view(), name='tag_add'),
|
||||
path('tags/import/', views.TagBulkImportView.as_view(), name='tag_import'),
|
||||
path('tags/edit/', views.TagBulkEditView.as_view(), name='tag_bulk_edit'),
|
||||
path('tags/delete/', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'),
|
||||
path('tags/<str:slug>/', views.TagView.as_view(), name='tag'),
|
||||
|
@ -13,14 +13,13 @@ from utilities.forms import ConfirmationForm
|
||||
from utilities.paginator import EnhancedPaginator
|
||||
from utilities.utils import shallow_compare_dict
|
||||
from utilities.views import (
|
||||
BulkDeleteView, BulkEditView, ObjectView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||
BulkDeleteView, BulkEditView, BulkImportView, ObjectView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||
ObjectPermissionRequiredMixin,
|
||||
)
|
||||
from . import filters, forms
|
||||
from . import filters, forms, tables
|
||||
from .models import ConfigContext, ImageAttachment, ObjectChange, ReportResult, Tag, TaggedItem
|
||||
from .reports import get_report, get_reports
|
||||
from .scripts import get_scripts, run_script
|
||||
from .tables import ConfigContextTable, ObjectChangeTable, TagTable, TaggedItemTable
|
||||
|
||||
|
||||
#
|
||||
@ -35,8 +34,7 @@ class TagListView(ObjectListView):
|
||||
)
|
||||
filterset = filters.TagFilterSet
|
||||
filterset_form = forms.TagFilterForm
|
||||
table = TagTable
|
||||
action_buttons = ()
|
||||
table = tables.TagTable
|
||||
|
||||
|
||||
class TagView(ObjectView):
|
||||
@ -52,7 +50,7 @@ class TagView(ObjectView):
|
||||
)
|
||||
|
||||
# Generate a table of all items tagged with this Tag
|
||||
items_table = TaggedItemTable(tagged_items)
|
||||
items_table = tables.TaggedItemTable(tagged_items)
|
||||
paginate = {
|
||||
'paginator_class': EnhancedPaginator,
|
||||
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
|
||||
@ -78,13 +76,20 @@ class TagDeleteView(ObjectDeleteView):
|
||||
default_return_url = 'extras:tag_list'
|
||||
|
||||
|
||||
class TagBulkImportView(BulkImportView):
|
||||
queryset = Tag.objects.all()
|
||||
model_form = forms.TagCSVForm
|
||||
table = tables.TagTable
|
||||
default_return_url = 'extras:tag_list'
|
||||
|
||||
|
||||
class TagBulkEditView(BulkEditView):
|
||||
queryset = Tag.objects.annotate(
|
||||
items=Count('extras_taggeditem_items', distinct=True)
|
||||
).order_by(
|
||||
'name'
|
||||
)
|
||||
table = TagTable
|
||||
table = tables.TagTable
|
||||
form = forms.TagBulkEditForm
|
||||
default_return_url = 'extras:tag_list'
|
||||
|
||||
@ -95,7 +100,7 @@ class TagBulkDeleteView(BulkDeleteView):
|
||||
).order_by(
|
||||
'name'
|
||||
)
|
||||
table = TagTable
|
||||
table = tables.TagTable
|
||||
default_return_url = 'extras:tag_list'
|
||||
|
||||
|
||||
@ -107,7 +112,7 @@ class ConfigContextListView(ObjectListView):
|
||||
queryset = ConfigContext.objects.all()
|
||||
filterset = filters.ConfigContextFilterSet
|
||||
filterset_form = forms.ConfigContextFilterForm
|
||||
table = ConfigContextTable
|
||||
table = tables.ConfigContextTable
|
||||
action_buttons = ('add',)
|
||||
|
||||
|
||||
@ -143,7 +148,7 @@ class ConfigContextEditView(ObjectEditView):
|
||||
class ConfigContextBulkEditView(BulkEditView):
|
||||
queryset = ConfigContext.objects.all()
|
||||
filterset = filters.ConfigContextFilterSet
|
||||
table = ConfigContextTable
|
||||
table = tables.ConfigContextTable
|
||||
form = forms.ConfigContextBulkEditForm
|
||||
default_return_url = 'extras:configcontext_list'
|
||||
|
||||
@ -155,7 +160,7 @@ class ConfigContextDeleteView(ObjectDeleteView):
|
||||
|
||||
class ConfigContextBulkDeleteView(BulkDeleteView):
|
||||
queryset = ConfigContext.objects.all()
|
||||
table = ConfigContextTable
|
||||
table = tables.ConfigContextTable
|
||||
default_return_url = 'extras:configcontext_list'
|
||||
|
||||
|
||||
@ -197,7 +202,7 @@ class ObjectChangeListView(ObjectListView):
|
||||
queryset = ObjectChange.objects.prefetch_related('user', 'changed_object_type')
|
||||
filterset = filters.ObjectChangeFilterSet
|
||||
filterset_form = forms.ObjectChangeFilterForm
|
||||
table = ObjectChangeTable
|
||||
table = tables.ObjectChangeTable
|
||||
template_name = 'extras/objectchange_list.html'
|
||||
action_buttons = ('export',)
|
||||
|
||||
@ -214,7 +219,7 @@ class ObjectChangeView(ObjectView):
|
||||
).exclude(
|
||||
pk=objectchange.pk
|
||||
)
|
||||
related_changes_table = ObjectChangeTable(
|
||||
related_changes_table = tables.ObjectChangeTable(
|
||||
data=related_changes[:50],
|
||||
orderable=False
|
||||
)
|
||||
@ -267,7 +272,7 @@ class ObjectChangeLogView(View):
|
||||
Q(changed_object_type=content_type, changed_object_id=obj.pk) |
|
||||
Q(related_object_type=content_type, related_object_id=obj.pk)
|
||||
)
|
||||
objectchanges_table = ObjectChangeTable(
|
||||
objectchanges_table = tables.ObjectChangeTable(
|
||||
data=objectchanges,
|
||||
orderable=False
|
||||
)
|
||||
|
@ -85,7 +85,7 @@
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>
|
||||
{{ tag.description }}
|
||||
{{ tag.description|placeholder }}
|
||||
</td>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -101,6 +101,12 @@
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header">Tags</li>
|
||||
<li{% if not perms.extras.view_tag %} class="disabled"{% endif %}>
|
||||
{% if perms.extras.add_tag %}
|
||||
<div class="buttons pull-right">
|
||||
<a href="{% url 'extras:tag_add' %}" class="btn btn-xs btn-success" title="Add"><i class="fa fa-plus"></i></a>
|
||||
<a href="{% url 'extras:tag_import' %}" class="btn btn-xs btn-info" title="Import"><i class="fa fa-download"></i></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<a href="{% url 'extras:tag_list' %}">Tags</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
Loading…
Reference in New Issue
Block a user