ソースを参照

Closes: #13918 - Add facility field (#15456)

* Fixes: #13918 - Add facilities field to Location model.

* Stupidly forgot to `git add`

* Fix errant reference to site.

* Misc cleanup

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
Daniel Sheppard 1 年間 前
コミット
19f577ccaf

+ 4 - 0
docs/models/dcim/location.md

@@ -26,3 +26,7 @@ The location's operational status.
 
 !!! tip
     Additional statuses may be defined by setting `Location.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter.
+
+### Facility
+
+Data center or facility designation for identifying the location.

+ 2 - 2
netbox/dcim/api/serializers_/sites.py

@@ -92,7 +92,7 @@ class LocationSerializer(NestedGroupModelSerializer):
     class Meta:
         model = Location
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'description', 'tags',
-            'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count', '_depth',
+            'id', 'url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'facility', 'description',
+            'tags', 'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count', '_depth',
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count', '_depth')

+ 2 - 1
netbox/dcim/filtersets.py

@@ -270,13 +270,14 @@ class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, OrganizationalM
 
     class Meta:
         model = Location
-        fields = ('id', 'name', 'slug', 'status', 'description')
+        fields = ('id', 'name', 'slug', 'status', '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)
         )
 

+ 1 - 1
netbox/dcim/forms/bulk_import.py

@@ -157,7 +157,7 @@ class LocationImportForm(NetBoxModelImportForm):
 
     class Meta:
         model = Location
-        fields = ('site', 'parent', 'name', 'slug', 'status', 'tenant', 'description', 'tags')
+        fields = ('site', 'parent', 'name', 'slug', 'status', 'tenant', 'facility', 'description', 'tags')
 
     def __init__(self, data=None, *args, **kwargs):
         super().__init__(data, *args, **kwargs)

+ 2 - 2
netbox/dcim/forms/model_forms.py

@@ -179,14 +179,14 @@ class LocationForm(TenancyForm, NetBoxModelForm):
     slug = SlugField()
 
     fieldsets = (
-        (_('Location'), ('site', 'parent', 'name', 'slug', 'status', 'description', 'tags')),
+        (_('Location'), ('site', 'parent', 'name', 'slug', 'status', 'facility', 'description', 'tags')),
         (_('Tenancy'), ('tenant_group', 'tenant')),
     )
 
     class Meta:
         model = Location
         fields = (
-            'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant', 'tags',
+            'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant', 'facility', 'tags',
         )
 
 

+ 18 - 0
netbox/dcim/migrations/0186_location_facility.py

@@ -0,0 +1,18 @@
+# Generated by Django 4.2.4 on 2024-03-17 02:21
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dcim', '0185_gfk_indexes'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='location',
+            name='facility',
+            field=models.CharField(blank=True, max_length=50),
+        ),
+    ]

+ 7 - 1
netbox/dcim/models/sites.py

@@ -275,6 +275,12 @@ class Location(ContactsMixin, ImageAttachmentsMixin, NestedGroupModel):
         blank=True,
         null=True
     )
+    facility = models.CharField(
+        verbose_name=_('facility'),
+        max_length=50,
+        blank=True,
+        help_text=_('Local facility ID or description')
+    )
 
     # Generic relations
     vlan_groups = GenericRelation(
@@ -284,7 +290,7 @@ class Location(ContactsMixin, ImageAttachmentsMixin, NestedGroupModel):
         related_query_name='location'
     )
 
-    clone_fields = ('site', 'parent', 'status', 'tenant', 'description')
+    clone_fields = ('site', 'parent', 'status', 'tenant', 'facility', 'description')
     prerequisite_models = (
         'dcim.Site',
     )

+ 2 - 1
netbox/dcim/search.py

@@ -132,10 +132,11 @@ class LocationIndex(SearchIndex):
     model = models.Location
     fields = (
         ('name', 100),
+        ('facility', 100),
         ('slug', 110),
         ('description', 500),
     )
-    display_attrs = ('site', 'status', 'tenant', 'description')
+    display_attrs = ('site', 'status', 'tenant', 'facility', 'description')
 
 
 @register_search

+ 5 - 3
netbox/dcim/tables/sites.py

@@ -152,7 +152,9 @@ class LocationTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
     class Meta(NetBoxTable.Meta):
         model = Location
         fields = (
-            'pk', 'id', 'name', 'site', 'status', 'tenant', 'tenant_group', 'rack_count', 'device_count', 'description',
-            'slug', 'contacts', 'tags', 'actions', 'created', 'last_updated',
+            'pk', 'id', 'name', 'site', 'status', 'facility', 'tenant', 'tenant_group', 'rack_count', 'device_count',
+            'description', 'slug', 'contacts', 'tags', 'actions', 'created', 'last_updated',
+        )
+        default_columns = (
+            'pk', 'name', 'site', 'status', 'facility', 'tenant', 'rack_count', 'device_count', 'description'
         )
-        default_columns = ('pk', 'name', 'site', 'status', 'tenant', 'rack_count', 'device_count', 'description')

+ 7 - 3
netbox/dcim/tests/test_filtersets.py

@@ -359,9 +359,9 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests):
             location.save()
 
         locations = (
-            Location(name='Location 1A', slug='location-1a', site=sites[0], parent=parent_locations[0], status=LocationStatusChoices.STATUS_PLANNED, description='foobar1'),
-            Location(name='Location 2A', slug='location-2a', site=sites[1], parent=parent_locations[1], status=LocationStatusChoices.STATUS_STAGING, description='foobar2'),
-            Location(name='Location 3A', slug='location-3a', site=sites[2], parent=parent_locations[2], status=LocationStatusChoices.STATUS_DECOMMISSIONING, description='foobar3'),
+            Location(name='Location 1A', slug='location-1a', site=sites[0], parent=parent_locations[0], status=LocationStatusChoices.STATUS_PLANNED, facility='Facility 1', description='foobar1'),
+            Location(name='Location 2A', slug='location-2a', site=sites[1], parent=parent_locations[1], status=LocationStatusChoices.STATUS_STAGING, facility='Facility 2', description='foobar2'),
+            Location(name='Location 3A', slug='location-3a', site=sites[2], parent=parent_locations[2], status=LocationStatusChoices.STATUS_DECOMMISSIONING, facility='Facility 3', description='foobar3'),
         )
         for location in locations:
             location.save()
@@ -390,6 +390,10 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests):
         params = {'status': [LocationStatusChoices.STATUS_PLANNED, LocationStatusChoices.STATUS_STAGING]}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
 
+    def test_facility(self):
+        params = {'facility': ['Facility 1', 'Facility 2']}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
     def test_description(self):
         params = {'description': ['foobar1', 'foobar2']}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

+ 1 - 0
netbox/dcim/tests/test_views.py

@@ -213,6 +213,7 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
             'slug': 'location-x',
             'site': site.pk,
             'status': LocationStatusChoices.STATUS_PLANNED,
+            'facility': 'Facility X',
             'tenant': tenant.pk,
             'description': 'A new location',
             'tags': [t.pk for t in tags],

+ 4 - 0
netbox/templates/dcim/location.html

@@ -54,6 +54,10 @@
             {{ object.tenant|linkify|placeholder }}
           </td>
         </tr>
+        <tr>
+          <th scope="row">{% trans "Facility" %}</th>
+          <td>{{ object.facility|placeholder }}</td>
+        </tr>
       </table>
     </div>
     {% include 'inc/panels/tags.html' %}