mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 01:41:22 -06:00
parent
d25605c261
commit
6b7d23d684
@ -16,6 +16,12 @@ A unique URL-friendly identifier. (This value will be used for filtering.) This
|
|||||||
|
|
||||||
The color to use when displaying the tag in the NetBox UI.
|
The color to use when displaying the tag in the NetBox UI.
|
||||||
|
|
||||||
|
### Weight
|
||||||
|
|
||||||
|
A numeric weight employed to influence the ordering of tags. Tags with a lower weight will be listed before those with higher weights. Values must be within the range **0** to **32767**.
|
||||||
|
|
||||||
|
!!! info "This field was introduced in NetBox v4.3."
|
||||||
|
|
||||||
### Object Types
|
### Object Types
|
||||||
|
|
||||||
The assignment of a tag may be limited to a prescribed set of objects. For example, it may be desirable to limit the application of a specific tag to only devices and virtual machines.
|
The assignment of a tag may be limited to a prescribed set of objects. For example, it may be desirable to limit the application of a specific tag to only devices and virtual machines.
|
||||||
|
@ -27,8 +27,8 @@ class TagSerializer(ValidatedModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Tag
|
model = Tag
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'object_types',
|
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'weight',
|
||||||
'tagged_items', 'created', 'last_updated',
|
'object_types', 'tagged_items', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'color', 'description')
|
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'color', 'description')
|
||||||
|
|
||||||
|
@ -450,7 +450,7 @@ class TagFilterSet(ChangeLoggedModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Tag
|
model = Tag
|
||||||
fields = ('id', 'name', 'slug', 'color', 'description', 'object_types')
|
fields = ('id', 'name', 'slug', 'color', 'weight', 'description', 'object_types')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -275,6 +275,10 @@ class TagBulkEditForm(BulkEditForm):
|
|||||||
max_length=200,
|
max_length=200,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
weight = forms.IntegerField(
|
||||||
|
label=_('Weight'),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
nullable_fields = ('description',)
|
nullable_fields = ('description',)
|
||||||
|
|
||||||
|
@ -232,10 +232,14 @@ class EventRuleImportForm(NetBoxModelImportForm):
|
|||||||
|
|
||||||
class TagImportForm(CSVModelForm):
|
class TagImportForm(CSVModelForm):
|
||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
weight = forms.IntegerField(
|
||||||
|
label=_('Weight'),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Tag
|
model = Tag
|
||||||
fields = ('name', 'slug', 'color', 'description')
|
fields = ('name', 'slug', 'color', 'weight', 'description')
|
||||||
|
|
||||||
|
|
||||||
class JournalEntryImportForm(NetBoxModelImportForm):
|
class JournalEntryImportForm(NetBoxModelImportForm):
|
||||||
|
@ -490,15 +490,19 @@ class TagForm(forms.ModelForm):
|
|||||||
queryset=ObjectType.objects.with_feature('tags'),
|
queryset=ObjectType.objects.with_feature('tags'),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
weight = forms.IntegerField(
|
||||||
|
label=_('Weight'),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
FieldSet('name', 'slug', 'color', 'description', 'object_types', name=_('Tag')),
|
FieldSet('name', 'slug', 'color', 'weight', 'description', 'object_types', name=_('Tag')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Tag
|
model = Tag
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'slug', 'color', 'description', 'object_types',
|
'name', 'slug', 'color', 'weight', 'description', 'object_types',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 5.2b1 on 2025-03-17 14:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('extras', '0123_remove_staging'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='tag',
|
||||||
|
options={'ordering': ('weight', 'name')},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='tag',
|
||||||
|
name='weight',
|
||||||
|
field=models.PositiveSmallIntegerField(default=0),
|
||||||
|
),
|
||||||
|
]
|
@ -40,13 +40,17 @@ class Tag(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, TagBase):
|
|||||||
blank=True,
|
blank=True,
|
||||||
help_text=_("The object type(s) to which this tag can be applied.")
|
help_text=_("The object type(s) to which this tag can be applied.")
|
||||||
)
|
)
|
||||||
|
weight = models.PositiveSmallIntegerField(
|
||||||
|
verbose_name=_('weight'),
|
||||||
|
default=0,
|
||||||
|
)
|
||||||
|
|
||||||
clone_fields = (
|
clone_fields = (
|
||||||
'color', 'description', 'object_types',
|
'color', 'description', 'object_types',
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ('weight', 'name')
|
||||||
verbose_name = _('tag')
|
verbose_name = _('tag')
|
||||||
verbose_name_plural = _('tags')
|
verbose_name_plural = _('tags')
|
||||||
|
|
||||||
|
@ -449,8 +449,8 @@ class TagTable(NetBoxTable):
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Tag
|
model = Tag
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'items', 'slug', 'color', 'description', 'object_types', 'created', 'last_updated',
|
'pk', 'id', 'name', 'items', 'slug', 'color', 'weight', 'description', 'object_types',
|
||||||
'actions',
|
'created', 'last_updated', 'actions',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'name', 'items', 'slug', 'color', 'description')
|
default_columns = ('pk', 'name', 'items', 'slug', 'color', 'description')
|
||||||
|
|
||||||
|
@ -513,6 +513,7 @@ class TagTest(APIViewTestCases.APIViewTestCase):
|
|||||||
{
|
{
|
||||||
'name': 'Tag 4',
|
'name': 'Tag 4',
|
||||||
'slug': 'tag-4',
|
'slug': 'tag-4',
|
||||||
|
'weight': 1000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'Tag 5',
|
'name': 'Tag 5',
|
||||||
@ -533,7 +534,7 @@ class TagTest(APIViewTestCases.APIViewTestCase):
|
|||||||
tags = (
|
tags = (
|
||||||
Tag(name='Tag 1', slug='tag-1'),
|
Tag(name='Tag 1', slug='tag-1'),
|
||||||
Tag(name='Tag 2', slug='tag-2'),
|
Tag(name='Tag 2', slug='tag-2'),
|
||||||
Tag(name='Tag 3', slug='tag-3'),
|
Tag(name='Tag 3', slug='tag-3', weight=26),
|
||||||
)
|
)
|
||||||
Tag.objects.bulk_create(tags)
|
Tag.objects.bulk_create(tags)
|
||||||
|
|
||||||
|
@ -1196,7 +1196,7 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
tags = (
|
tags = (
|
||||||
Tag(name='Tag 1', slug='tag-1', color='ff0000', description='foobar1'),
|
Tag(name='Tag 1', slug='tag-1', color='ff0000', description='foobar1'),
|
||||||
Tag(name='Tag 2', slug='tag-2', color='00ff00', description='foobar2'),
|
Tag(name='Tag 2', slug='tag-2', color='00ff00', description='foobar2'),
|
||||||
Tag(name='Tag 3', slug='tag-3', color='0000ff'),
|
Tag(name='Tag 3', slug='tag-3', color='0000ff', weight=1000),
|
||||||
)
|
)
|
||||||
Tag.objects.bulk_create(tags)
|
Tag.objects.bulk_create(tags)
|
||||||
tags[0].object_types.add(object_types['site'])
|
tags[0].object_types.add(object_types['site'])
|
||||||
@ -1249,6 +1249,13 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
['Tag 2', 'Tag 3']
|
['Tag 2', 'Tag 3']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_weight(self):
|
||||||
|
params = {'weight': [1000]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
|
params = {'weight': [0]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||||
|
|
||||||
|
|
||||||
class TaggedItemFilterSetTestCase(TestCase):
|
class TaggedItemFilterSetTestCase(TestCase):
|
||||||
queryset = TaggedItem.objects.all()
|
queryset = TaggedItem.objects.all()
|
||||||
|
@ -10,6 +10,40 @@ from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMac
|
|||||||
|
|
||||||
class TagTest(TestCase):
|
class TagTest(TestCase):
|
||||||
|
|
||||||
|
def test_default_ordering_weight_then_name_is_set(self):
|
||||||
|
Tag.objects.create(name='Tag 1', slug='tag-1', weight=100)
|
||||||
|
Tag.objects.create(name='Tag 2', slug='tag-2')
|
||||||
|
Tag.objects.create(name='Tag 3', slug='tag-3', weight=10)
|
||||||
|
Tag.objects.create(name='Tag 4', slug='tag-4', weight=10)
|
||||||
|
|
||||||
|
tags = Tag.objects.all()
|
||||||
|
|
||||||
|
self.assertEqual(tags[0].slug, 'tag-2')
|
||||||
|
self.assertEqual(tags[1].slug, 'tag-3')
|
||||||
|
self.assertEqual(tags[2].slug, 'tag-4')
|
||||||
|
self.assertEqual(tags[3].slug, 'tag-1')
|
||||||
|
|
||||||
|
def test_tag_related_manager_ordering_weight_then_name(self):
|
||||||
|
tags = [
|
||||||
|
Tag.objects.create(name='Tag 1', slug='tag-1', weight=100),
|
||||||
|
Tag.objects.create(name='Tag 2', slug='tag-2'),
|
||||||
|
Tag.objects.create(name='Tag 3', slug='tag-3', weight=10),
|
||||||
|
Tag.objects.create(name='Tag 4', slug='tag-4', weight=10),
|
||||||
|
]
|
||||||
|
|
||||||
|
site = Site.objects.create(name='Site 1')
|
||||||
|
for tag in tags:
|
||||||
|
site.tags.add(tag)
|
||||||
|
site.save()
|
||||||
|
|
||||||
|
site = Site.objects.first()
|
||||||
|
tags = site.tags.all()
|
||||||
|
|
||||||
|
self.assertEqual(tags[0].slug, 'tag-2')
|
||||||
|
self.assertEqual(tags[1].slug, 'tag-3')
|
||||||
|
self.assertEqual(tags[2].slug, 'tag-4')
|
||||||
|
self.assertEqual(tags[3].slug, 'tag-1')
|
||||||
|
|
||||||
def test_create_tag_unicode(self):
|
def test_create_tag_unicode(self):
|
||||||
tag = Tag(name='Testing Unicode: 台灣')
|
tag = Tag(name='Testing Unicode: 台灣')
|
||||||
tag.save()
|
tag.save()
|
||||||
|
@ -441,8 +441,8 @@ class TagTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
|
|
||||||
tags = (
|
tags = (
|
||||||
Tag(name='Tag 1', slug='tag-1'),
|
Tag(name='Tag 1', slug='tag-1'),
|
||||||
Tag(name='Tag 2', slug='tag-2'),
|
Tag(name='Tag 2', slug='tag-2', weight=1),
|
||||||
Tag(name='Tag 3', slug='tag-3'),
|
Tag(name='Tag 3', slug='tag-3', weight=32767),
|
||||||
)
|
)
|
||||||
Tag.objects.bulk_create(tags)
|
Tag.objects.bulk_create(tags)
|
||||||
|
|
||||||
@ -451,13 +451,14 @@ class TagTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
'slug': 'tag-x',
|
'slug': 'tag-x',
|
||||||
'color': 'c0c0c0',
|
'color': 'c0c0c0',
|
||||||
'comments': 'Some comments',
|
'comments': 'Some comments',
|
||||||
|
'weight': 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
cls.csv_data = (
|
cls.csv_data = (
|
||||||
"name,slug,color,description",
|
"name,slug,color,description,weight",
|
||||||
"Tag 4,tag-4,ff0000,Fourth tag",
|
"Tag 4,tag-4,ff0000,Fourth tag,0",
|
||||||
"Tag 5,tag-5,00ff00,Fifth tag",
|
"Tag 5,tag-5,00ff00,Fifth tag,1111",
|
||||||
"Tag 6,tag-6,0000ff,Sixth tag",
|
"Tag 6,tag-6,0000ff,Sixth tag,0",
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.csv_update_data = (
|
cls.csv_update_data = (
|
||||||
|
@ -455,7 +455,8 @@ class TagsMixin(models.Model):
|
|||||||
which is a `TaggableManager` instance.
|
which is a `TaggableManager` instance.
|
||||||
"""
|
"""
|
||||||
tags = TaggableManager(
|
tags = TaggableManager(
|
||||||
through='extras.TaggedItem'
|
through='extras.TaggedItem',
|
||||||
|
ordering=('weight', 'name'),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -28,6 +28,10 @@
|
|||||||
<span class="color-label" style="background-color: #{{ object.color }}"> </span>
|
<span class="color-label" style="background-color: #{{ object.color }}"> </span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Weight" %}</th>
|
||||||
|
<td>{{ object.weight }}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Tagged Items" %}</th>
|
<th scope="row">{% trans "Tagged Items" %}</th>
|
||||||
<td>
|
<td>
|
||||||
|
Loading…
Reference in New Issue
Block a user