소스 검색

Closes #2557: Added object view for tags

Jeremy Stretch 7 년 전
부모
커밋
3366a6ae3d
7개의 변경된 파일155개의 추가작업 그리고 7개의 파일을 삭제
  1. 1 0
      CHANGELOG.md
  2. 5 0
      netbox/extras/forms.py
  3. 29 1
      netbox/extras/tables.py
  4. 1 0
      netbox/extras/urls.py
  5. 46 5
      netbox/extras/views.py
  6. 69 0
      netbox/templates/extras/tag.html
  7. 4 1
      netbox/templates/extras/tag_list.html

+ 1 - 0
CHANGELOG.md

@@ -3,6 +3,7 @@ v2.4.8 (FUTURE)
 ## Enhancements
 
 * [#2490](https://github.com/digitalocean/netbox/issues/2490) - Added bulk editing for config contexts
+* [#2557](https://github.com/digitalocean/netbox/issues/2557) - Added object view for tags
 
 ## Bug Fixes
 

+ 5 - 0
netbox/extras/forms.py

@@ -208,6 +208,11 @@ class AddRemoveTagsForm(forms.Form):
         self.fields['remove_tags'] = TagField(required=False)
 
 
+class TagFilterForm(BootstrapMixin, forms.Form):
+    model = Tag
+    q = forms.CharField(required=False, label='Search')
+
+
 #
 # Config contexts
 #

+ 29 - 1
netbox/extras/tables.py

@@ -1,7 +1,8 @@
 from __future__ import unicode_literals
 
 import django_tables2 as tables
-from taggit.models import Tag
+from django_tables2.utils import Accessor
+from taggit.models import Tag, TaggedItem
 
 from utilities.tables import BaseTable, BooleanColumn, ToggleColumn
 from .models import ConfigContext, ObjectChange
@@ -15,6 +16,14 @@ TAG_ACTIONS = """
 {% endif %}
 """
 
+TAGGED_ITEM = """
+{% if value.get_absolute_url %}
+    <a href="{{ value.get_absolute_url }}">{{ value }}</a>
+{% else %}
+    {{ value }}
+{% endif %}
+"""
+
 CONFIGCONTEXT_ACTIONS = """
 {% if perms.extras.change_configcontext %}
     <a href="{% url 'extras:configcontext_edit' pk=record.pk %}" class="btn btn-xs btn-warning"><i class="glyphicon glyphicon-pencil" aria-hidden="true"></i></a>
@@ -55,6 +64,10 @@ OBJECTCHANGE_REQUEST_ID = """
 
 class TagTable(BaseTable):
     pk = ToggleColumn()
+    name = tables.LinkColumn(
+        viewname='extras:tag',
+        args=[Accessor('slug')]
+    )
     actions = tables.TemplateColumn(
         template_code=TAG_ACTIONS,
         attrs={'td': {'class': 'text-right'}},
@@ -66,6 +79,21 @@ class TagTable(BaseTable):
         fields = ('pk', 'name', 'items', 'slug', 'actions')
 
 
+class TaggedItemTable(BaseTable):
+    content_object = tables.TemplateColumn(
+        template_code=TAGGED_ITEM,
+        orderable=False,
+        verbose_name='Object'
+    )
+    content_type = tables.Column(
+        verbose_name='Type'
+    )
+
+    class Meta(BaseTable.Meta):
+        model = TaggedItem
+        fields = ('content_object', 'content_type')
+
+
 class ConfigContextTable(BaseTable):
     pk = ToggleColumn()
     name = tables.LinkColumn()

+ 1 - 0
netbox/extras/urls.py

@@ -9,6 +9,7 @@ urlpatterns = [
 
     # Tags
     url(r'^tags/$', views.TagListView.as_view(), name='tag_list'),
+    url(r'^tags/(?P<slug>[\w-]+)/$', views.TagView.as_view(), name='tag'),
     url(r'^tags/(?P<slug>[\w-]+)/edit/$', views.TagEditView.as_view(), name='tag_edit'),
     url(r'^tags/(?P<slug>[\w-]+)/delete/$', views.TagDeleteView.as_view(), name='tag_delete'),
     url(r'^tags/delete/$', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'),

+ 46 - 5
netbox/extras/views.py

@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 
 from django import template
+from django.conf import settings
 from django.contrib import messages
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.contrib.contenttypes.models import ContentType
@@ -9,18 +10,20 @@ from django.http import Http404
 from django.shortcuts import get_object_or_404, redirect, render
 from django.utils.safestring import mark_safe
 from django.views.generic import View
-from taggit.models import Tag
+from django_tables2 import RequestConfig
+from taggit.models import Tag, TaggedItem
 
 from utilities.forms import ConfirmationForm
+from utilities.paginator import EnhancedPaginator
 from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView
 from . import filters
 from .forms import (
     ConfigContextForm, ConfigContextBulkEditForm, ConfigContextFilterForm, ImageAttachmentForm, ObjectChangeFilterForm,
-    TagForm,
+    TagFilterForm, TagForm,
 )
 from .models import ConfigContext, ImageAttachment, ObjectChange, ReportResult
 from .reports import get_report, get_reports
-from .tables import ConfigContextTable, ObjectChangeTable, TagTable
+from .tables import ConfigContextTable, ObjectChangeTable, TagTable, TaggedItemTable
 
 
 #
@@ -28,11 +31,45 @@ from .tables import ConfigContextTable, ObjectChangeTable, TagTable
 #
 
 class TagListView(ObjectListView):
-    queryset = Tag.objects.annotate(items=Count('taggit_taggeditem_items')).order_by('name')
+    queryset = Tag.objects.annotate(
+        items=Count('taggit_taggeditem_items')
+    ).order_by(
+        'name'
+    )
+    filter = filters.TagFilter
+    filter_form = TagFilterForm
     table = TagTable
     template_name = 'extras/tag_list.html'
 
 
+class TagView(View):
+
+    def get(self, request, slug):
+
+        tag = get_object_or_404(Tag, slug=slug)
+        tagged_items = TaggedItem.objects.filter(
+            tag=tag
+        ).select_related(
+            'content_type'
+        ).prefetch_related(
+            'content_object'
+        )
+
+        # Generate a table of all items tagged with this Tag
+        items_table = TaggedItemTable(tagged_items)
+        paginate = {
+            'klass': EnhancedPaginator,
+            'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
+        }
+        RequestConfig(request, paginate).configure(items_table)
+
+        return render(request, 'extras/tag.html', {
+            'tag': tag,
+            'items_count': tagged_items.count(),
+            'items_table': items_table,
+        })
+
+
 class TagEditView(PermissionRequiredMixin, ObjectEditView):
     permission_required = 'taggit.change_tag'
     model = Tag
@@ -48,7 +85,11 @@ class TagDeleteView(PermissionRequiredMixin, ObjectDeleteView):
 
 class TagBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'circuits.delete_circuittype'
-    queryset = Tag.objects.annotate(items=Count('taggit_taggeditem_items')).order_by('name')
+    queryset = Tag.objects.annotate(
+        items=Count('taggit_taggeditem_items')
+    ).order_by(
+        'name'
+    )
     table = TagTable
     default_return_url = 'extras:tag_list'
 

+ 69 - 0
netbox/templates/extras/tag.html

@@ -0,0 +1,69 @@
+{% extends '_base.html' %}
+{% load helpers %}
+
+{% block header %}
+    <div class="row">
+        <div class="col-sm-8 col-md-9">
+            <ol class="breadcrumb">
+                <li><a href="{% url 'extras:tag_list' %}">Tags</a></li>
+                <li>{{ tag }}</li>
+            </ol>
+        </div>
+        <div class="col-sm-4 col-md-3">
+            <form action="{% url 'extras:tag_list' %}" method="get">
+                <div class="input-group">
+                    <input type="text" name="q" class="form-control" />
+                    <span class="input-group-btn">
+                        <button type="submit" class="btn btn-primary">
+                            <span class="fa fa-search" aria-hidden="true"></span>
+                        </button>
+                    </span>
+                </div>
+            </form>
+        </div>
+    </div>
+    <div class="pull-right">
+        {% if perms.taggit.change_tag %}
+            <a href="{% url 'extras:tag_edit' slug=tag.slug %}?return_url={% url 'extras:tag' slug=tag.slug %}" class="btn btn-warning">
+                <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
+                Edit this tag
+            </a>
+        {% endif %}
+    </div>
+    <h1>{% block title %}Tag: {{ tag }}{% endblock %}</h1>
+{% endblock %}
+
+{% block content %}
+    <div class="row">
+        <div class="col-md-6">
+            <div class="panel panel-default">
+                <div class="panel-heading">
+                    <strong>Tag</strong>
+                </div>
+                <table class="table table-hover panel-body attr-table">
+                    <tr>
+                        <td>Name</td>
+                        <td>
+                            {{ tag.name }}
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>Slug</td>
+                        <td>
+                            {{ tag.slug }}
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>Tagged Items</td>
+                        <td>
+                            {{ items_count }}
+                        </td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+        <div class="col-md-6">
+            {% include 'panel_table.html' with table=items_table heading='Tagged Objects' %}
+        </div>
+    </div>
+{% endblock %}

+ 4 - 1
netbox/templates/extras/tag_list.html

@@ -4,8 +4,11 @@
 {% block content %}
 <h1>{% block title %}Tags{% endblock %}</h1>
 <div class="row">
-	<div class="col-md-12">
+	<div class="col-md-9">
         {% include 'utilities/obj_table.html' with bulk_delete_url='extras:tag_bulk_delete' %}
     </div>
+    <div class="col-md-3">
+		{% include 'inc/search_panel.html' %}
+    </div>
 </div>
 {% endblock %}