From 03a1c48b54d0bc4e62ef452b0919548f0241edfb Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 22 May 2018 12:22:46 -0400 Subject: [PATCH] Added list and utility views for tags --- netbox/extras/forms.py | 24 ++++++++++++++- netbox/extras/tables.py | 28 ++++++++++++++++++ netbox/extras/urls.py | 6 ++++ netbox/extras/views.py | 42 +++++++++++++++++++++++++-- netbox/templates/extras/tag_list.html | 11 +++++++ netbox/templates/inc/nav_menu.html | 5 +++- 6 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 netbox/extras/tables.py create mode 100644 netbox/templates/extras/tag_list.html diff --git a/netbox/extras/forms.py b/netbox/extras/forms.py index a923ae596..9088d1b3d 100644 --- a/netbox/extras/forms.py +++ b/netbox/extras/forms.py @@ -4,12 +4,17 @@ from collections import OrderedDict from django import forms from django.contrib.contenttypes.models import ContentType +from taggit.models import Tag -from utilities.forms import BootstrapMixin, BulkEditForm, LaxURLField +from utilities.forms import BootstrapMixin, BulkEditForm, LaxURLField, SlugField from .constants import CF_FILTER_DISABLED, CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CF_TYPE_URL from .models import CustomField, CustomFieldValue, ImageAttachment +# +# Custom fields +# + def get_custom_fields_for_model(content_type, filterable_only=False, bulk_edit=False): """ Retrieve all CustomFields applicable to the given ContentType @@ -162,6 +167,23 @@ class CustomFieldFilterForm(forms.Form): self.fields[name] = field +# +# Tags +# +# + +class TagForm(BootstrapMixin, forms.ModelForm): + slug = SlugField() + + class Meta: + model = Tag + fields = ['name', 'slug'] + + +# +# Image attachments +# + class ImageAttachmentForm(BootstrapMixin, forms.ModelForm): class Meta: diff --git a/netbox/extras/tables.py b/netbox/extras/tables.py new file mode 100644 index 000000000..921b9f273 --- /dev/null +++ b/netbox/extras/tables.py @@ -0,0 +1,28 @@ +from __future__ import unicode_literals + +import django_tables2 as tables +from taggit.models import Tag + +from utilities.tables import BaseTable, ToggleColumn + +TAG_ACTIONS = """ +{% if perms.taggit.change_tag %} + +{% endif %} +{% if perms.taggit.delete_tag %} + +{% endif %} +""" + + +class TagTable(BaseTable): + pk = ToggleColumn() + actions = tables.TemplateColumn( + template_code=TAG_ACTIONS, + attrs={'td': {'class': 'text-right'}}, + verbose_name='' + ) + + class Meta(BaseTable.Meta): + model = Tag + fields = ('pk', 'name', 'items') diff --git a/netbox/extras/urls.py b/netbox/extras/urls.py index 13e50a229..d3c200334 100644 --- a/netbox/extras/urls.py +++ b/netbox/extras/urls.py @@ -7,6 +7,12 @@ from extras import views app_name = 'extras' urlpatterns = [ + # Tags + url(r'^tags/$', views.TagListView.as_view(), name='tag_list'), + url(r'^tags/(?P[\w-]+)/edit/$', views.TagEditView.as_view(), name='tag_edit'), + url(r'^tags/(?P[\w-]+)/delete/$', views.TagDeleteView.as_view(), name='tag_delete'), + url(r'^tags/delete/$', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'), + # Image attachments url(r'^image-attachments/(?P\d+)/edit/$', views.ImageAttachmentEditView.as_view(), name='imageattachment_edit'), url(r'^image-attachments/(?P\d+)/delete/$', views.ImageAttachmentDeleteView.as_view(), name='imageattachment_delete'), diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 3f7c0435b..130437356 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -2,16 +2,52 @@ from __future__ import unicode_literals from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin +from django.db.models import Count from django.http import Http404 -from django.shortcuts import get_object_or_404, redirect, render +from django.shortcuts import get_object_or_404, redirect, render, reverse from django.utils.safestring import mark_safe from django.views.generic import View +from taggit.models import Tag from utilities.forms import ConfirmationForm -from utilities.views import ObjectDeleteView, ObjectEditView -from .forms import ImageAttachmentForm +from utilities.views import BulkDeleteView, ObjectDeleteView, ObjectEditView, ObjectListView +from .forms import ImageAttachmentForm, TagForm from .models import ImageAttachment, ReportResult, UserAction from .reports import get_report, get_reports +from .tables import TagTable + + +# +# Tags +# + +class TagListView(ObjectListView): + queryset = Tag.objects.annotate(items=Count('taggit_taggeditem_items')).order_by('name') + table = TagTable + template_name = 'extras/tag_list.html' + + +class TagEditView(PermissionRequiredMixin, ObjectEditView): + permission_required = 'taggit.change_tag' + model = Tag + model_form = TagForm + + def get_return_url(self, request, obj): + return reverse('extras:tag', kwargs={'slug': obj.slug}) + + +class TagDeleteView(PermissionRequiredMixin, ObjectDeleteView): + permission_required = 'taggit.delete_tag' + model = Tag + default_return_url = 'extras:tag_list' + + +class TagBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): + permission_required = 'circuits.delete_circuittype' + cls = Tag + queryset = Tag.objects.annotate(items=Count('taggit_taggeditem_items')).order_by('name') + table = TagTable + default_return_url = 'extras:tag_list' # diff --git a/netbox/templates/extras/tag_list.html b/netbox/templates/extras/tag_list.html new file mode 100644 index 000000000..3136991a0 --- /dev/null +++ b/netbox/templates/extras/tag_list.html @@ -0,0 +1,11 @@ +{% extends '_base.html' %} +{% load buttons %} + +{% block content %} +

{% block title %}Tags{% endblock %}

+
+
+ {% include 'utilities/obj_table.html' with bulk_delete_url='extras:tag_bulk_delete' %} +
+
+{% endblock %} diff --git a/netbox/templates/inc/nav_menu.html b/netbox/templates/inc/nav_menu.html index a85647993..2c47ad85b 100644 --- a/netbox/templates/inc/nav_menu.html +++ b/netbox/templates/inc/nav_menu.html @@ -16,7 +16,7 @@