Merge pull request #18859 from netbox-community/17602-comments-field-for-nested-models

Closes #17602: adds comments field to NestedGroupModel children
This commit is contained in:
bctiemann 2025-03-19 09:50:11 -04:00 committed by GitHub
commit cd10087b2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 364 additions and 117 deletions

View File

@ -27,7 +27,7 @@ class RegionSerializer(NestedGroupModelSerializer):
model = Region
fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
'created', 'last_updated', 'site_count', 'prefix_count', '_depth',
'created', 'last_updated', 'site_count', 'prefix_count', 'comments', '_depth',
]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth')
@ -41,7 +41,7 @@ class SiteGroupSerializer(NestedGroupModelSerializer):
model = SiteGroup
fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
'created', 'last_updated', 'site_count', 'prefix_count', '_depth',
'created', 'last_updated', 'site_count', 'prefix_count', 'comments', '_depth',
]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth')
@ -93,6 +93,6 @@ class LocationSerializer(NestedGroupModelSerializer):
fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'facility',
'description', 'tags', 'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count',
'prefix_count', '_depth',
'prefix_count', 'comments', '_depth',
]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count', '_depth')

View File

@ -11,7 +11,8 @@ from ipam.filtersets import PrimaryIPFilterSet
from ipam.models import ASN, IPAddress, VLANTranslationPolicy, VRF
from netbox.choices import ColorChoices
from netbox.filtersets import (
BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet,
BaseFilterSet, ChangeLoggedModelFilterSet, NestedGroupModelFilterSet, NetBoxModelFilterSet,
OrganizationalModelFilterSet,
)
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
from tenancy.models import *
@ -81,7 +82,7 @@ __all__ = (
)
class RegionFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
class RegionFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=Region.objects.all(),
label=_('Parent region (ID)'),
@ -111,7 +112,7 @@ class RegionFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
fields = ('id', 'name', 'slug', 'description')
class SiteGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
class SiteGroupFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
label=_('Parent site group (ID)'),
@ -205,7 +206,7 @@ class SiteFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe
return queryset.filter(qs_filter).distinct()
class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, OrganizationalModelFilterSet):
class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, NestedGroupModelFilterSet):
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region',
@ -275,13 +276,13 @@ class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, OrganizationalM
fields = ('id', 'name', 'slug', 'facility', 'description')
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(name__icontains=value) |
Q(facility__icontains=value) |
Q(description__icontains=value)
)
# extended in order to include querying on Location.facility
queryset = super().search(queryset, name, value)
if value.strip():
queryset = queryset | queryset.model.objects.filter(facility__icontains=value)
return queryset
class RackRoleFilterSet(OrganizationalModelFilterSet):

View File

@ -78,12 +78,13 @@ class RegionBulkEditForm(NetBoxModelBulkEditForm):
max_length=200,
required=False
)
comments = CommentField()
model = Region
fieldsets = (
FieldSet('parent', 'description'),
)
nullable_fields = ('parent', 'description')
nullable_fields = ('parent', 'description', 'comments')
class SiteGroupBulkEditForm(NetBoxModelBulkEditForm):
@ -97,12 +98,13 @@ class SiteGroupBulkEditForm(NetBoxModelBulkEditForm):
max_length=200,
required=False
)
comments = CommentField()
model = SiteGroup
fieldsets = (
FieldSet('parent', 'description'),
)
nullable_fields = ('parent', 'description')
nullable_fields = ('parent', 'description', 'comments')
class SiteBulkEditForm(NetBoxModelBulkEditForm):
@ -197,12 +199,13 @@ class LocationBulkEditForm(NetBoxModelBulkEditForm):
max_length=200,
required=False
)
comments = CommentField()
model = Location
fieldsets = (
FieldSet('site', 'parent', 'status', 'tenant', 'description'),
)
nullable_fields = ('parent', 'tenant', 'description')
nullable_fields = ('parent', 'tenant', 'description', 'comments')
class RackRoleBulkEditForm(NetBoxModelBulkEditForm):

View File

@ -68,7 +68,7 @@ class RegionImportForm(NetBoxModelImportForm):
class Meta:
model = Region
fields = ('name', 'slug', 'parent', 'description', 'tags')
fields = ('name', 'slug', 'parent', 'description', 'tags', 'comments')
class SiteGroupImportForm(NetBoxModelImportForm):
@ -82,7 +82,7 @@ class SiteGroupImportForm(NetBoxModelImportForm):
class Meta:
model = SiteGroup
fields = ('name', 'slug', 'parent', 'description')
fields = ('name', 'slug', 'parent', 'description', 'comments', 'tags')
class SiteImportForm(NetBoxModelImportForm):
@ -160,7 +160,10 @@ class LocationImportForm(NetBoxModelImportForm):
class Meta:
model = Location
fields = ('site', 'parent', 'name', 'slug', 'status', 'tenant', 'facility', 'description', 'tags')
fields = (
'site', 'parent', 'name', 'slug', 'status', 'tenant', 'facility', 'description',
'tags', 'comments',
)
def __init__(self, data=None, *args, **kwargs):
super().__init__(data, *args, **kwargs)

View File

@ -78,6 +78,7 @@ class RegionForm(NetBoxModelForm):
required=False
)
slug = SlugField()
comments = CommentField()
fieldsets = (
FieldSet('parent', 'name', 'slug', 'description', 'tags'),
@ -86,7 +87,7 @@ class RegionForm(NetBoxModelForm):
class Meta:
model = Region
fields = (
'parent', 'name', 'slug', 'description', 'tags',
'parent', 'name', 'slug', 'description', 'tags', 'comments',
)
@ -97,6 +98,7 @@ class SiteGroupForm(NetBoxModelForm):
required=False
)
slug = SlugField()
comments = CommentField()
fieldsets = (
FieldSet('parent', 'name', 'slug', 'description', 'tags'),
@ -105,7 +107,7 @@ class SiteGroupForm(NetBoxModelForm):
class Meta:
model = SiteGroup
fields = (
'parent', 'name', 'slug', 'description', 'tags',
'parent', 'name', 'slug', 'description', 'comments', 'tags',
)
@ -179,6 +181,7 @@ class LocationForm(TenancyForm, NetBoxModelForm):
}
)
slug = SlugField()
comments = CommentField()
fieldsets = (
FieldSet('site', 'parent', 'name', 'slug', 'status', 'facility', 'description', 'tags', name=_('Location')),
@ -188,7 +191,8 @@ class LocationForm(TenancyForm, NetBoxModelForm):
class Meta:
model = Location
fields = (
'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant', 'facility', 'tags',
'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant',
'facility', 'tags', 'comments',
)

View File

@ -0,0 +1,26 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0201_add_power_outlet_status'),
]
operations = [
migrations.AddField(
model_name='location',
name='comments',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='region',
name='comments',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='sitegroup',
name='comments',
field=models.TextField(blank=True),
),
]

View File

@ -144,6 +144,7 @@ class LocationIndex(SearchIndex):
('facility', 100),
('slug', 110),
('description', 500),
('comments', 5000),
)
display_attrs = ('site', 'status', 'tenant', 'facility', 'description')
@ -317,6 +318,7 @@ class RegionIndex(SearchIndex):
('name', 100),
('slug', 110),
('description', 500),
('comments', 5000),
)
display_attrs = ('parent', 'description')
@ -343,6 +345,7 @@ class SiteGroupIndex(SearchIndex):
('name', 100),
('slug', 110),
('description', 500),
('comments', 5000),
)
display_attrs = ('parent', 'description')

View File

@ -32,12 +32,15 @@ class RegionTable(ContactsColumnMixin, NetBoxTable):
tags = columns.TagColumn(
url_name='dcim:region_list'
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
class Meta(NetBoxTable.Meta):
model = Region
fields = (
'pk', 'id', 'name', 'slug', 'site_count', 'description', 'contacts', 'tags', 'created', 'last_updated',
'actions',
'pk', 'id', 'name', 'slug', 'site_count', 'description', 'comments', 'contacts', 'tags',
'created', 'last_updated', 'actions',
)
default_columns = ('pk', 'name', 'site_count', 'description')
@ -59,12 +62,15 @@ class SiteGroupTable(ContactsColumnMixin, NetBoxTable):
tags = columns.TagColumn(
url_name='dcim:sitegroup_list'
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
class Meta(NetBoxTable.Meta):
model = SiteGroup
fields = (
'pk', 'id', 'name', 'slug', 'site_count', 'description', 'contacts', 'tags', 'created', 'last_updated',
'actions',
'pk', 'id', 'name', 'slug', 'site_count', 'description', 'comments', 'contacts', 'tags',
'created', 'last_updated', 'actions',
)
default_columns = ('pk', 'name', 'site_count', 'description')
@ -153,12 +159,15 @@ class LocationTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
actions = columns.ActionsColumn(
extra_buttons=LOCATION_BUTTONS
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
class Meta(NetBoxTable.Meta):
model = Location
fields = (
'pk', 'id', 'name', 'site', 'status', 'facility', 'tenant', 'tenant_group', 'rack_count', 'device_count',
'description', 'slug', 'contacts', 'tags', 'actions', 'created', 'last_updated',
'description', 'slug', 'comments', 'contacts', 'tags', 'actions', 'created', 'last_updated',
)
default_columns = (
'pk', 'name', 'site', 'status', 'facility', 'tenant', 'rack_count', 'device_count', 'description'

View File

@ -74,6 +74,7 @@ class RegionTest(APIViewTestCases.APIViewTestCase):
{
'name': 'Region 4',
'slug': 'region-4',
'comments': 'this is region 4, not region 5',
},
{
'name': 'Region 5',
@ -86,13 +87,14 @@ class RegionTest(APIViewTestCases.APIViewTestCase):
]
bulk_update_data = {
'description': 'New description',
'comments': 'New comments',
}
@classmethod
def setUpTestData(cls):
Region.objects.create(name='Region 1', slug='region-1')
Region.objects.create(name='Region 2', slug='region-2')
Region.objects.create(name='Region 2', slug='region-2', comments='what in the world is happening?')
Region.objects.create(name='Region 3', slug='region-3')
@ -103,26 +105,30 @@ class SiteGroupTest(APIViewTestCases.APIViewTestCase):
{
'name': 'Site Group 4',
'slug': 'site-group-4',
'comments': '',
},
{
'name': 'Site Group 5',
'slug': 'site-group-5',
'comments': 'not actually empty',
},
{
'name': 'Site Group 6',
'slug': 'site-group-6',
'comments': 'Do I really exist?',
},
]
bulk_update_data = {
'description': 'New description',
'comments': 'I do exist!',
}
@classmethod
def setUpTestData(cls):
SiteGroup.objects.create(name='Site Group 1', slug='site-group-1')
SiteGroup.objects.create(name='Site Group 2', slug='site-group-2')
SiteGroup.objects.create(name='Site Group 3', slug='site-group-3')
SiteGroup.objects.create(name='Site Group 2', slug='site-group-2', comments='')
SiteGroup.objects.create(name='Site Group 3', slug='site-group-3', comments='Hi!')
class SiteTest(APIViewTestCases.APIViewTestCase):
@ -212,12 +218,14 @@ class LocationTest(APIViewTestCases.APIViewTestCase):
name='Parent Location 1',
slug='parent-location-1',
status=LocationStatusChoices.STATUS_ACTIVE,
comments='First!'
),
Location.objects.create(
site=sites[1],
name='Parent Location 2',
slug='parent-location-2',
status=LocationStatusChoices.STATUS_ACTIVE,
comments='Second!'
),
)
@ -227,6 +235,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase):
slug='location-1',
parent=parent_locations[0],
status=LocationStatusChoices.STATUS_ACTIVE,
comments='Third!'
)
Location.objects.create(
site=sites[0],
@ -250,6 +259,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase):
'site': sites[1].pk,
'parent': parent_locations[1].pk,
'status': LocationStatusChoices.STATUS_PLANNED,
'comments': '',
},
{
'name': 'Test Location 5',
@ -257,6 +267,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase):
'site': sites[1].pk,
'parent': parent_locations[1].pk,
'status': LocationStatusChoices.STATUS_PLANNED,
'comments': 'Somebody should check on this location',
},
{
'name': 'Test Location 6',

View File

@ -67,9 +67,15 @@ class RegionTestCase(TestCase, ChangeLoggedFilterSetTests):
def setUpTestData(cls):
parent_regions = (
Region(name='Region 1', slug='region-1', description='foobar1'),
Region(name='Region 2', slug='region-2', description='foobar2'),
Region(name='Region 3', slug='region-3', description='foobar3'),
Region(
name='Region 1', slug='region-1', description='foobar1', comments="There's nothing that",
),
Region(
name='Region 2', slug='region-2', description='foobar2', comments='a hundred men or more',
),
Region(
name='Region 3', slug='region-3', description='foobar3', comments='could ever do'
),
)
for region in parent_regions:
region.save()
@ -100,6 +106,13 @@ class RegionTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'q': 'foobar1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_q_comments(self):
params = {'q': 'there'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
params = {'q': 'hundred men could'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
def test_name(self):
params = {'name': ['Region 1', 'Region 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -148,13 +161,17 @@ class SiteGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
SiteGroup(name='Site Group 2A', slug='site-group-2a', parent=parent_groups[1]),
SiteGroup(name='Site Group 2B', slug='site-group-2b', parent=parent_groups[1]),
SiteGroup(name='Site Group 3A', slug='site-group-3a', parent=parent_groups[2]),
SiteGroup(name='Site Group 3B', slug='site-group-3b', parent=parent_groups[2]),
SiteGroup(
name='Site Group 3B', slug='site-group-3b', parent=parent_groups[2], comments='this is a parent group',
),
)
for site_group in groups:
site_group.save()
child_groups = (
SiteGroup(name='Site Group 1A1', slug='site-group-1a1', parent=groups[0]),
SiteGroup(
name='Site Group 1A1', slug='site-group-1a1', parent=groups[0], comments='this is a child group',
),
SiteGroup(name='Site Group 1B1', slug='site-group-1b1', parent=groups[1]),
SiteGroup(name='Site Group 2A1', slug='site-group-2a1', parent=groups[2]),
SiteGroup(name='Site Group 2B1', slug='site-group-2b1', parent=groups[3]),
@ -168,6 +185,13 @@ class SiteGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'q': 'foobar1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_q_comments(self):
params = {'q': 'this'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'q': 'child'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_name(self):
params = {'name': ['Site Group 1', 'Site Group 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -401,6 +425,7 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests):
status=LocationStatusChoices.STATUS_PLANNED,
facility='Facility 1',
description='foobar1',
comments='',
),
Location(
name='Location 2A',
@ -410,6 +435,7 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests):
status=LocationStatusChoices.STATUS_STAGING,
facility='Facility 2',
description='foobar2',
comments='First comment!',
),
Location(
name='Location 3A',
@ -419,6 +445,7 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests):
status=LocationStatusChoices.STATUS_DECOMMISSIONING,
facility='Facility 3',
description='foobar3',
comments='_This_ is a **bold comment**',
),
)
for location in locations:
@ -436,6 +463,13 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'q': 'foobar1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_q_comments(self):
params = {'q': 'this'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
params = {'q': 'comment'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self):
params = {'name': ['Location 1', 'Location 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -25,8 +25,10 @@ class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
# Create three Regions
regions = (
Region(name='Region 1', slug='region-1'),
Region(name='Region 2', slug='region-2'),
Region(name='Region 1', slug='region-1', comments=''),
Region(
name='Region 2', slug='region-2', comments="It's going to take a lot to drag me away from you"
),
Region(name='Region 3', slug='region-3'),
)
for region in regions:
@ -40,13 +42,14 @@ class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
'parent': regions[2].pk,
'description': 'A new region',
'tags': [t.pk for t in tags],
'comments': 'This comment is really exciting!',
}
cls.csv_data = (
"name,slug,description",
"Region 4,region-4,Fourth region",
"Region 5,region-5,Fifth region",
"Region 6,region-6,Sixth region",
"name,slug,description,comments",
"Region 4,region-4,Fourth region,",
"Region 5,region-5,Fifth region,hi guys",
"Region 6,region-6,Sixth region,bye guys",
)
cls.csv_update_data = (
@ -58,6 +61,7 @@ class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
cls.bulk_edit_data = {
'description': 'New description',
'comments': 'This comment is super exciting!!!',
}
@ -69,7 +73,7 @@ class SiteGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
# Create three SiteGroups
sitegroups = (
SiteGroup(name='Site Group 1', slug='site-group-1'),
SiteGroup(name='Site Group 1', slug='site-group-1', comments='Still here'),
SiteGroup(name='Site Group 2', slug='site-group-2'),
SiteGroup(name='Site Group 3', slug='site-group-3'),
)
@ -84,24 +88,26 @@ class SiteGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
'parent': sitegroups[2].pk,
'description': 'A new site group',
'tags': [t.pk for t in tags],
'comments': 'still here',
}
cls.csv_data = (
"name,slug,description",
"Site Group 4,site-group-4,Fourth site group",
"Site Group 5,site-group-5,Fifth site group",
"Site Group 6,site-group-6,Sixth site group",
"name,slug,description,comments",
"Site Group 4,site-group-4,Fourth site group,",
"Site Group 5,site-group-5,Fifth site group,still hear",
"Site Group 6,site-group-6,Sixth site group,"
)
cls.csv_update_data = (
"id,name,description",
f"{sitegroups[0].pk},Site Group 7,Fourth site group7",
f"{sitegroups[1].pk},Site Group 8,Fifth site group8",
f"{sitegroups[2].pk},Site Group 0,Sixth site group9",
"id,name,description,comments",
f"{sitegroups[0].pk},Site Group 7,Fourth site group7,",
f"{sitegroups[1].pk},Site Group 8,Fifth site group8,when will it end",
f"{sitegroups[2].pk},Site Group 0,Sixth site group9,",
)
cls.bulk_edit_data = {
'description': 'New description',
'comments': 'the end',
}
@ -202,6 +208,7 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
site=site,
status=LocationStatusChoices.STATUS_ACTIVE,
tenant=tenant,
comments='',
),
Location(
name='Location 2',
@ -209,6 +216,7 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
site=site,
status=LocationStatusChoices.STATUS_ACTIVE,
tenant=tenant,
comments='First comment!',
),
Location(
name='Location 3',
@ -216,6 +224,7 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
site=site,
status=LocationStatusChoices.STATUS_ACTIVE,
tenant=tenant,
comments='_This_ is a **bold comment**',
),
)
for location in locations:
@ -232,24 +241,26 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
'tenant': tenant.pk,
'description': 'A new location',
'tags': [t.pk for t in tags],
'comments': 'This comment is really boring',
}
cls.csv_data = (
"site,tenant,name,slug,status,description",
"Site 1,Tenant 1,Location 4,location-4,planned,Fourth location",
"Site 1,Tenant 1,Location 5,location-5,planned,Fifth location",
"Site 1,Tenant 1,Location 6,location-6,planned,Sixth location",
"site,tenant,name,slug,status,description,comments",
"Site 1,Tenant 1,Location 4,location-4,planned,Fourth location,",
"Site 1,Tenant 1,Location 5,location-5,planned,Fifth location,",
"Site 1,Tenant 1,Location 6,location-6,planned,Sixth location,hi!",
)
cls.csv_update_data = (
"id,name,description",
f"{locations[0].pk},Location 7,Fourth location7",
f"{locations[1].pk},Location 8,Fifth location8",
f"{locations[2].pk},Location 0,Sixth location9",
"id,name,description,comments",
f"{locations[0].pk},Location 7,Fourth location7,Useful comment",
f"{locations[1].pk},Location 8,Fifth location8,unuseful comment",
f"{locations[2].pk},Location 0,Sixth location9,",
)
cls.bulk_edit_data = {
'description': 'New description',
'comments': 'This comment is also really boring',
}

View File

@ -329,3 +329,19 @@ class OrganizationalModelFilterSet(NetBoxModelFilterSet):
models.Q(slug__icontains=value) |
models.Q(description__icontains=value)
)
class NestedGroupModelFilterSet(NetBoxModelFilterSet):
"""
A base FilterSet for models that inherit from NestedGroupModel
"""
def search(self, queryset, name, value):
if value.strip():
queryset = queryset.filter(
models.Q(name__icontains=value) |
models.Q(slug__icontains=value) |
models.Q(description__icontains=value) |
models.Q(comments__icontains=value)
)
return queryset

View File

@ -150,6 +150,10 @@ class NestedGroupModel(NetBoxFeatureSet, MPTTModel):
max_length=200,
blank=True
)
comments = models.TextField(
verbose_name=_('comments'),
blank=True
)
objects = TreeManager()

View File

@ -62,6 +62,7 @@
</div>
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/comments.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">

View File

@ -41,6 +41,7 @@
</div>
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/comments.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">

View File

@ -41,6 +41,7 @@
</div>
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/comments.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">

View File

@ -32,6 +32,7 @@
</table>
</div>
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/comments.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">

View File

@ -40,6 +40,7 @@
</table>
</div>
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/comments.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">

View File

@ -40,6 +40,7 @@
</table>
</div>
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/comments.html' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">

View File

@ -26,7 +26,7 @@ class ContactGroupSerializer(NestedGroupModelSerializer):
model = ContactGroup
fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
'created', 'last_updated', 'contact_count', '_depth',
'created', 'last_updated', 'contact_count', 'comments', '_depth',
]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'contact_count', '_depth')

View File

@ -19,7 +19,7 @@ class TenantGroupSerializer(NestedGroupModelSerializer):
model = TenantGroup
fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
'created', 'last_updated', 'tenant_count', '_depth',
'created', 'last_updated', 'tenant_count', 'comments', '_depth',
]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'tenant_count', '_depth')

View File

@ -2,7 +2,7 @@ import django_filters
from django.db.models import Q
from django.utils.translation import gettext as _
from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet
from netbox.filtersets import NestedGroupModelFilterSet, NetBoxModelFilterSet, OrganizationalModelFilterSet
from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter
from .models import *
@ -22,7 +22,7 @@ __all__ = (
# Contacts
#
class ContactGroupFilterSet(OrganizationalModelFilterSet):
class ContactGroupFilterSet(NestedGroupModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=ContactGroup.objects.all(),
label=_('Parent contact group (ID)'),
@ -168,7 +168,7 @@ class ContactModelFilterSet(django_filters.FilterSet):
# Tenancy
#
class TenantGroupFilterSet(OrganizationalModelFilterSet):
class TenantGroupFilterSet(NestedGroupModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=TenantGroup.objects.all(),
label=_('Parent tenant group (ID)'),

View File

@ -33,9 +33,10 @@ class TenantGroupBulkEditForm(NetBoxModelBulkEditForm):
max_length=200,
required=False
)
comments = CommentField()
model = TenantGroup
nullable_fields = ('parent', 'description')
nullable_fields = ('parent', 'description', 'comments')
class TenantBulkEditForm(NetBoxModelBulkEditForm):
@ -67,12 +68,13 @@ class ContactGroupBulkEditForm(NetBoxModelBulkEditForm):
max_length=200,
required=False
)
comments = CommentField()
model = ContactGroup
fieldsets = (
FieldSet('parent', 'description'),
)
nullable_fields = ('parent', 'description')
nullable_fields = ('parent', 'description', 'comments')
class ContactRoleBulkEditForm(NetBoxModelBulkEditForm):

View File

@ -31,7 +31,7 @@ class TenantGroupImportForm(NetBoxModelImportForm):
class Meta:
model = TenantGroup
fields = ('name', 'slug', 'parent', 'description', 'tags')
fields = ('name', 'slug', 'parent', 'description', 'tags', 'comments')
class TenantImportForm(NetBoxModelImportForm):
@ -65,7 +65,7 @@ class ContactGroupImportForm(NetBoxModelImportForm):
class Meta:
model = ContactGroup
fields = ('name', 'slug', 'parent', 'description', 'tags')
fields = ('name', 'slug', 'parent', 'description', 'tags', 'comments')
class ContactRoleImportForm(NetBoxModelImportForm):

View File

@ -27,6 +27,7 @@ class TenantGroupForm(NetBoxModelForm):
required=False
)
slug = SlugField()
comments = CommentField()
fieldsets = (
FieldSet('parent', 'name', 'slug', 'description', 'tags', name=_('Tenant Group')),
@ -35,7 +36,7 @@ class TenantGroupForm(NetBoxModelForm):
class Meta:
model = TenantGroup
fields = [
'parent', 'name', 'slug', 'description', 'tags',
'parent', 'name', 'slug', 'description', 'tags', 'comments'
]
@ -70,6 +71,7 @@ class ContactGroupForm(NetBoxModelForm):
required=False
)
slug = SlugField()
comments = CommentField()
fieldsets = (
FieldSet('parent', 'name', 'slug', 'description', 'tags', name=_('Contact Group')),
@ -77,7 +79,7 @@ class ContactGroupForm(NetBoxModelForm):
class Meta:
model = ContactGroup
fields = ('parent', 'name', 'slug', 'description', 'tags')
fields = ('parent', 'name', 'slug', 'description', 'tags', 'comments')
class ContactRoleForm(NetBoxModelForm):

View File

@ -0,0 +1,21 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tenancy', '0017_natural_ordering'),
]
operations = [
migrations.AddField(
model_name='contactgroup',
name='comments',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='tenantgroup',
name='comments',
field=models.TextField(blank=True),
),
]

View File

@ -25,6 +25,7 @@ class ContactGroupIndex(SearchIndex):
('name', 100),
('slug', 110),
('description', 500),
('comments', 5000),
)
display_attrs = ('description',)
@ -59,5 +60,6 @@ class TenantGroupIndex(SearchIndex):
('name', 100),
('slug', 110),
('description', 500),
('comments', 5000),
)
display_attrs = ('description',)

View File

@ -27,11 +27,15 @@ class ContactGroupTable(NetBoxTable):
tags = columns.TagColumn(
url_name='tenancy:contactgroup_list'
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
class Meta(NetBoxTable.Meta):
model = ContactGroup
fields = (
'pk', 'name', 'contact_count', 'description', 'slug', 'tags', 'created', 'last_updated', 'actions',
'pk', 'name', 'contact_count', 'description', 'comments', 'slug', 'tags', 'created',
'last_updated', 'actions',
)
default_columns = ('pk', 'name', 'contact_count', 'description')

View File

@ -24,11 +24,15 @@ class TenantGroupTable(NetBoxTable):
tags = columns.TagColumn(
url_name='tenancy:tenantgroup_list'
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
class Meta(NetBoxTable.Meta):
model = TenantGroup
fields = (
'pk', 'id', 'name', 'tenant_count', 'description', 'slug', 'tags', 'created', 'last_updated', 'actions',
'pk', 'id', 'name', 'tenant_count', 'description', 'comments', 'slug', 'tags', 'created',
'last_updated', 'actions',
)
default_columns = ('pk', 'name', 'tenant_count', 'description')

View File

@ -21,6 +21,7 @@ class TenantGroupTest(APIViewTestCases.APIViewTestCase):
brief_fields = ['_depth', 'description', 'display', 'id', 'name', 'slug', 'tenant_count', 'url']
bulk_update_data = {
'description': 'New description',
'comments': 'New Comment',
}
@classmethod
@ -28,12 +29,17 @@ class TenantGroupTest(APIViewTestCases.APIViewTestCase):
parent_tenant_groups = (
TenantGroup.objects.create(name='Parent Tenant Group 1', slug='parent-tenant-group-1'),
TenantGroup.objects.create(name='Parent Tenant Group 2', slug='parent-tenant-group-2'),
TenantGroup.objects.create(
name='Parent Tenant Group 2', slug='parent-tenant-group-2', comments='Parent Group 2 comment',
),
)
TenantGroup.objects.create(name='Tenant Group 1', slug='tenant-group-1', parent=parent_tenant_groups[0])
TenantGroup.objects.create(name='Tenant Group 2', slug='tenant-group-2', parent=parent_tenant_groups[0])
TenantGroup.objects.create(name='Tenant Group 3', slug='tenant-group-3', parent=parent_tenant_groups[0])
TenantGroup.objects.create(
name='Tenant Group 3', slug='tenant-group-3', parent=parent_tenant_groups[0],
comments='Tenant Group 3 comment'
)
cls.create_data = [
{
@ -50,6 +56,7 @@ class TenantGroupTest(APIViewTestCases.APIViewTestCase):
'name': 'Tenant Group 6',
'slug': 'tenant-group-6',
'parent': parent_tenant_groups[1].pk,
'comments': 'Tenant Group 6 comment',
},
]
@ -107,13 +114,18 @@ class ContactGroupTest(APIViewTestCases.APIViewTestCase):
def setUpTestData(cls):
parent_contact_groups = (
ContactGroup.objects.create(name='Parent Contact Group 1', slug='parent-contact-group-1'),
ContactGroup.objects.create(
name='Parent Contact Group 1', slug='parent-contact-group-1', comments='Parent 1 comment'
),
ContactGroup.objects.create(name='Parent Contact Group 2', slug='parent-contact-group-2'),
)
ContactGroup.objects.create(name='Contact Group 1', slug='contact-group-1', parent=parent_contact_groups[0])
ContactGroup.objects.create(name='Contact Group 2', slug='contact-group-2', parent=parent_contact_groups[0])
ContactGroup.objects.create(name='Contact Group 3', slug='contact-group-3', parent=parent_contact_groups[0])
ContactGroup.objects.create(
name='Contact Group 3', slug='contact-group-3', parent=parent_contact_groups[0],
comments='Child Group 3 comment',
)
cls.create_data = [
{
@ -125,11 +137,13 @@ class ContactGroupTest(APIViewTestCases.APIViewTestCase):
'name': 'Contact Group 5',
'slug': 'contact-group-5',
'parent': parent_contact_groups[1].pk,
'comments': '',
},
{
'name': 'Contact Group 6',
'slug': 'contact-group-6',
'parent': parent_contact_groups[1].pk,
'comments': 'Child Group 6 comment',
},
]

View File

@ -16,7 +16,7 @@ class TenantGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
parent_tenant_groups = (
TenantGroup(name='Tenant Group 1', slug='tenant-group-1'),
TenantGroup(name='Tenant Group 2', slug='tenant-group-2'),
TenantGroup(name='Tenant Group 2', slug='tenant-group-2', comments='Parent group 2 comment'),
TenantGroup(name='Tenant Group 3', slug='tenant-group-3'),
)
for tenant_group in parent_tenant_groups:
@ -27,7 +27,8 @@ class TenantGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
name='Tenant Group 1A',
slug='tenant-group-1a',
parent=parent_tenant_groups[0],
description='foobar1'
description='foobar1',
comments='Tenant Group 1A comment',
),
TenantGroup(
name='Tenant Group 2A',
@ -48,7 +49,10 @@ class TenantGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
child_tenant_groups = (
TenantGroup(name='Tenant Group 1A1', slug='tenant-group-1a1', parent=tenant_groups[0]),
TenantGroup(name='Tenant Group 2A1', slug='tenant-group-2a1', parent=tenant_groups[1]),
TenantGroup(name='Tenant Group 3A1', slug='tenant-group-3a1', parent=tenant_groups[2]),
TenantGroup(
name='Tenant Group 3A1', slug='tenant-group-3a1', parent=tenant_groups[2],
comments='Tenant Group 3A1 comment',
),
)
for tenant_group in child_tenant_groups:
tenant_group.save()
@ -57,6 +61,13 @@ class TenantGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'q': 'foobar1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_q_comments(self):
params = {'q': 'parent'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
params = {'q': 'comment'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
def test_name(self):
params = {'name': ['Tenant Group 1', 'Tenant Group 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -139,7 +150,7 @@ class ContactGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
parent_contact_groups = (
ContactGroup(name='Contact Group 1', slug='contact-group-1'),
ContactGroup(name='Contact Group 2', slug='contact-group-2'),
ContactGroup(name='Contact Group 2', slug='contact-group-2', comments='Parent group 2'),
ContactGroup(name='Contact Group 3', slug='contact-group-3'),
)
for contact_group in parent_contact_groups:
@ -162,14 +173,18 @@ class ContactGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
name='Contact Group 3A',
slug='contact-group-3a',
parent=parent_contact_groups[2],
description='foobar3'
description='foobar3',
comments='Contact Group 3A comment, not a parent',
),
)
for contact_group in contact_groups:
contact_group.save()
child_contact_groups = (
ContactGroup(name='Contact Group 1A1', slug='contact-group-1a1', parent=contact_groups[0]),
ContactGroup(
name='Contact Group 1A1', slug='contact-group-1a1', parent=contact_groups[0],
comments='Contact Group 1A1 comment',
),
ContactGroup(name='Contact Group 2A1', slug='contact-group-2a1', parent=contact_groups[1]),
ContactGroup(name='Contact Group 3A1', slug='contact-group-3a1', parent=contact_groups[2]),
)
@ -180,6 +195,13 @@ class ContactGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'q': 'foobar1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_q_comments(self):
params = {'q': 'parent'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'q': '1A1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_name(self):
params = {'name': ['Contact Group 1', 'Contact Group 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -15,7 +15,7 @@ class TenantGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
tenant_groups = (
TenantGroup(name='Tenant Group 1', slug='tenant-group-1'),
TenantGroup(name='Tenant Group 2', slug='tenant-group-2'),
TenantGroup(name='Tenant Group 2', slug='tenant-group-2', comments='Tenant Group 2 comment'),
TenantGroup(name='Tenant Group 3', slug='tenant-group-3'),
)
for tenanantgroup in tenant_groups:
@ -28,24 +28,26 @@ class TenantGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
'slug': 'tenant-group-x',
'description': 'A new tenant group',
'tags': [t.pk for t in tags],
'comments': 'Tenant Group X comment',
}
cls.csv_data = (
"name,slug,description",
"Tenant Group 4,tenant-group-4,Fourth tenant group",
"Tenant Group 5,tenant-group-5,Fifth tenant group",
"Tenant Group 6,tenant-group-6,Sixth tenant group",
"name,slug,description,comments",
"Tenant Group 4,tenant-group-4,Fourth tenant group,",
"Tenant Group 5,tenant-group-5,Fifth tenant group,",
"Tenant Group 6,tenant-group-6,Sixth tenant group,Sixth tenant group comment",
)
cls.csv_update_data = (
"id,name,description",
f"{tenant_groups[0].pk},Tenant Group 7,Fourth tenant group7",
f"{tenant_groups[1].pk},Tenant Group 8,Fifth tenant group8",
f"{tenant_groups[2].pk},Tenant Group 0,Sixth tenant group9",
"id,name,description,comments",
f"{tenant_groups[0].pk},Tenant Group 7,Fourth tenant group7,Group 7 comment",
f"{tenant_groups[1].pk},Tenant Group 8,Fifth tenant group8,",
f"{tenant_groups[2].pk},Tenant Group 0,Sixth tenant group9,",
)
cls.bulk_edit_data = {
'description': 'New description',
'comments': 'New comment',
}
@ -106,7 +108,7 @@ class ContactGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
def setUpTestData(cls):
contact_groups = (
ContactGroup(name='Contact Group 1', slug='contact-group-1'),
ContactGroup(name='Contact Group 1', slug='contact-group-1', comments='Comment 1'),
ContactGroup(name='Contact Group 2', slug='contact-group-2'),
ContactGroup(name='Contact Group 3', slug='contact-group-3'),
)
@ -120,24 +122,26 @@ class ContactGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
'slug': 'contact-group-x',
'description': 'A new contact group',
'tags': [t.pk for t in tags],
'comments': 'Form data comment',
}
cls.csv_data = (
"name,slug,description",
"Contact Group 4,contact-group-4,Fourth contact group",
"Contact Group 5,contact-group-5,Fifth contact group",
"Contact Group 6,contact-group-6,Sixth contact group",
"name,slug,description,comments",
"Contact Group 4,contact-group-4,Fourth contact group,",
"Contact Group 5,contact-group-5,Fifth contact group,Fifth comment",
"Contact Group 6,contact-group-6,Sixth contact group,",
)
cls.csv_update_data = (
"id,name,description",
f"{contact_groups[0].pk},Contact Group 7,Fourth contact group7",
f"{contact_groups[1].pk},Contact Group 8,Fifth contact group8",
f"{contact_groups[2].pk},Contact Group 0,Sixth contact group9",
"id,name,description,comments",
f"{contact_groups[0].pk},Contact Group 7,Fourth contact group7,",
f"{contact_groups[1].pk},Contact Group 8,Fifth contact group8,Group 8 comment",
f"{contact_groups[2].pk},Contact Group 0,Sixth contact group9,",
)
cls.bulk_edit_data = {
'description': 'New description',
'comments': 'Bulk update comment',
}

View File

@ -26,7 +26,7 @@ class WirelessLANGroupSerializer(NestedGroupModelSerializer):
model = WirelessLANGroup
fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
'created', 'last_updated', 'wirelesslan_count', '_depth',
'created', 'last_updated', 'wirelesslan_count', 'comments', '_depth',
]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'wirelesslan_count', '_depth')

View File

@ -5,7 +5,7 @@ from dcim.choices import LinkStatusChoices
from dcim.base_filtersets import ScopedFilterSet
from dcim.models import Interface
from ipam.models import VLAN
from netbox.filtersets import OrganizationalModelFilterSet, NetBoxModelFilterSet
from netbox.filtersets import NestedGroupModelFilterSet, NetBoxModelFilterSet
from tenancy.filtersets import TenancyFilterSet
from utilities.filters import TreeNodeMultipleChoiceFilter
from .choices import *
@ -18,7 +18,7 @@ __all__ = (
)
class WirelessLANGroupFilterSet(OrganizationalModelFilterSet):
class WirelessLANGroupFilterSet(NestedGroupModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=WirelessLANGroup.objects.all()
)

View File

@ -32,12 +32,13 @@ class WirelessLANGroupBulkEditForm(NetBoxModelBulkEditForm):
max_length=200,
required=False
)
comments = CommentField()
model = WirelessLANGroup
fieldsets = (
FieldSet('parent', 'description'),
)
nullable_fields = ('parent', 'description')
nullable_fields = ('parent', 'description', 'comments')
class WirelessLANBulkEditForm(ScopedBulkEditForm, NetBoxModelBulkEditForm):

View File

@ -30,7 +30,7 @@ class WirelessLANGroupImportForm(NetBoxModelImportForm):
class Meta:
model = WirelessLANGroup
fields = ('name', 'slug', 'parent', 'description', 'tags')
fields = ('name', 'slug', 'parent', 'description', 'tags', 'comments')
class WirelessLANImportForm(ScopedImportForm, NetBoxModelImportForm):

View File

@ -24,6 +24,7 @@ class WirelessLANGroupForm(NetBoxModelForm):
required=False
)
slug = SlugField()
comments = CommentField()
fieldsets = (
FieldSet('parent', 'name', 'slug', 'description', 'tags', name=_('Wireless LAN Group')),
@ -32,7 +33,7 @@ class WirelessLANGroupForm(NetBoxModelForm):
class Meta:
model = WirelessLANGroup
fields = [
'parent', 'name', 'slug', 'description', 'tags',
'parent', 'name', 'slug', 'description', 'tags', 'comments',
]

View File

@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wireless', '0013_natural_ordering'),
]
operations = [
migrations.AddField(
model_name='wirelesslangroup',
name='comments',
field=models.TextField(blank=True),
),
]

View File

@ -21,6 +21,7 @@ class WirelessLANGroupIndex(SearchIndex):
('name', 100),
('slug', 110),
('description', 500),
('comments', 5000),
)
display_attrs = ('description',)

View File

@ -24,10 +24,12 @@ class WirelessLANGroupTest(APIViewTestCases.APIViewTestCase):
{
'name': 'Wireless LAN Group 4',
'slug': 'wireless-lan-group-4',
'comments': '',
},
{
'name': 'Wireless LAN Group 5',
'slug': 'wireless-lan-group-5',
'comments': 'LAN Group 5 comment',
},
{
'name': 'Wireless LAN Group 6',
@ -36,6 +38,7 @@ class WirelessLANGroupTest(APIViewTestCases.APIViewTestCase):
]
bulk_update_data = {
'description': 'New description',
'comments': 'New comment',
}
@classmethod

View File

@ -21,7 +21,10 @@ class WirelessLANGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
parent_groups = (
WirelessLANGroup(name='Wireless LAN Group 1', slug='wireless-lan-group-1', description='A'),
WirelessLANGroup(name='Wireless LAN Group 2', slug='wireless-lan-group-2', description='B'),
WirelessLANGroup(name='Wireless LAN Group 3', slug='wireless-lan-group-3', description='C'),
WirelessLANGroup(
name='Wireless LAN Group 3', slug='wireless-lan-group-3', description='C',
comments='Parent Group 3 comment',
),
)
for group in parent_groups:
group.save()
@ -38,10 +41,15 @@ class WirelessLANGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
slug='wireless-lan-group-1b',
parent=parent_groups[0],
description='foobar2',
comments='Child Group 1B comment',
),
WirelessLANGroup(name='Wireless LAN Group 2A', slug='wireless-lan-group-2a', parent=parent_groups[1]),
WirelessLANGroup(name='Wireless LAN Group 2B', slug='wireless-lan-group-2b', parent=parent_groups[1]),
WirelessLANGroup(name='Wireless LAN Group 3A', slug='wireless-lan-group-3a', parent=parent_groups[2]),
WirelessLANGroup(
name='Wireless LAN Group 3A', slug='wireless-lan-group-3a', parent=parent_groups[2],
comments='Wireless LAN Group 3A comment',
),
WirelessLANGroup(name='Wireless LAN Group 3B', slug='wireless-lan-group-3b', parent=parent_groups[2]),
)
for group in groups:
@ -62,6 +70,13 @@ class WirelessLANGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'q': 'foobar1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_q_comments(self):
params = {'q': 'parent'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
params = {'q': 'comment'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
def test_name(self):
params = {'name': ['Wireless LAN Group 1', 'Wireless LAN Group 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -16,7 +16,9 @@ class WirelessLANGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
groups = (
WirelessLANGroup(name='Wireless LAN Group 1', slug='wireless-lan-group-1'),
WirelessLANGroup(name='Wireless LAN Group 2', slug='wireless-lan-group-2'),
WirelessLANGroup(
name='Wireless LAN Group 2', slug='wireless-lan-group-2', comments='LAN Group 2 comment',
),
WirelessLANGroup(name='Wireless LAN Group 3', slug='wireless-lan-group-3'),
)
for group in groups:
@ -30,24 +32,26 @@ class WirelessLANGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
'parent': groups[2].pk,
'description': 'A new wireless LAN group',
'tags': [t.pk for t in tags],
'comments': 'LAN Group X comment',
}
cls.csv_data = (
"name,slug,description",
"Wireless LAN Group 4,wireless-lan-group-4,Fourth wireless LAN group",
"Wireless LAN Group 5,wireless-lan-group-5,Fifth wireless LAN group",
"Wireless LAN Group 6,wireless-lan-group-6,Sixth wireless LAN group",
"name,slug,description,comments",
"Wireless LAN Group 4,wireless-lan-group-4,Fourth wireless LAN group,",
"Wireless LAN Group 5,wireless-lan-group-5,Fifth wireless LAN group,",
"Wireless LAN Group 6,wireless-lan-group-6,Sixth wireless LAN group,LAN Group 6 comment",
)
cls.csv_update_data = (
"id,name,description",
f"{groups[0].pk},Wireless LAN Group 7,Fourth wireless LAN group7",
f"{groups[1].pk},Wireless LAN Group 8,Fifth wireless LAN group8",
f"{groups[2].pk},Wireless LAN Group 0,Sixth wireless LAN group9",
"id,name,description,comments",
f"{groups[0].pk},Wireless LAN Group 7,Fourth wireless LAN group7,Group 7 comment",
f"{groups[1].pk},Wireless LAN Group 8,Fifth wireless LAN group8,",
f"{groups[2].pk},Wireless LAN Group 0,Sixth wireless LAN group9,",
)
cls.bulk_edit_data = {
'description': 'New description',
'comments': 'New Comments',
}