00ff00
)'),
+ }
+
+
class AddRemoveTagsForm(forms.Form):
def __init__(self, *args, **kwargs):
diff --git a/netbox/extras/models/tags.py b/netbox/extras/models/tags.py
index d5792ebda..9bb90f21e 100644
--- a/netbox/extras/models/tags.py
+++ b/netbox/extras/models/tags.py
@@ -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(
diff --git a/netbox/extras/tests/test_views.py b/netbox/extras/tests/test_views.py
index 9ad29fd80..b3abf5b22 100644
--- a/netbox/extras/tests/test_views.py
+++ b/netbox/extras/tests/test_views.py
@@ -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',
}
diff --git a/netbox/extras/urls.py b/netbox/extras/urls.py
index 3eee303a3..3007e6524 100644
--- a/netbox/extras/urls.py
+++ b/netbox/extras/urls.py
@@ -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/