mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 04:22:01 -06:00
Closes #11494: Enable filtering objects by create/update request IDs
This commit is contained in:
parent
5b81986bb3
commit
6e4c4c4342
@ -37,6 +37,7 @@ A new ASN range model has been introduced to facilitate the provisioning of new
|
||||
* [#10729](https://github.com/netbox-community/netbox/issues/10729) - Add date & time custom field type
|
||||
* [#11254](https://github.com/netbox-community/netbox/issues/11254) - Introduce the `X-Request-ID` HTTP header to annotate the unique ID of each request for change logging
|
||||
* [#11440](https://github.com/netbox-community/netbox/issues/11440) - Add an `enabled` field for device type interfaces
|
||||
* [#11494](https://github.com/netbox-community/netbox/issues/11494) - Enable filtering objects by create/update request IDs
|
||||
* [#11517](https://github.com/netbox-community/netbox/issues/11517) - Standardize the inclusion of related objects across the entire UI
|
||||
* [#11584](https://github.com/netbox-community/netbox/issues/11584) - Add a list view for contact assignments
|
||||
* [#11625](https://github.com/netbox-community/netbox/issues/11625) - Add HTMX support to ObjectEditView
|
||||
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-16 20:06
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('extras', '0089_customfield_is_cloneable'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='objectchange',
|
||||
name='request_id',
|
||||
field=models.UUIDField(db_index=True, editable=False),
|
||||
),
|
||||
]
|
@ -31,7 +31,8 @@ class ObjectChange(models.Model):
|
||||
editable=False
|
||||
)
|
||||
request_id = models.UUIDField(
|
||||
editable=False
|
||||
editable=False,
|
||||
db_index=True
|
||||
)
|
||||
action = models.CharField(
|
||||
max_length=50,
|
||||
|
@ -6,6 +6,7 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import TestCase
|
||||
|
||||
from circuits.models import Provider
|
||||
from dcim.filtersets import SiteFilterSet
|
||||
from dcim.models import DeviceRole, DeviceType, Manufacturer, Platform, Rack, Region, Site, SiteGroup
|
||||
from dcim.models import Location
|
||||
from extras.choices import *
|
||||
@ -924,3 +925,71 @@ class ObjectChangeTestCase(TestCase, BaseFilterSetTests):
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||
params = {'changed_object_type_id': [ContentType.objects.get(app_label='dcim', model='site').pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||
|
||||
|
||||
class ChangeLoggedFilterSetTestCase(TestCase):
|
||||
"""
|
||||
Evaluate base ChangeLoggedFilterSet filters using the Site model.
|
||||
"""
|
||||
queryset = Site.objects.all()
|
||||
filterset = SiteFilterSet
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
content_type = ContentType.objects.get_for_model(Site)
|
||||
|
||||
# Create three sites
|
||||
sites = (
|
||||
Site(name='Site 1', slug='site-1'),
|
||||
Site(name='Site 2', slug='site-2'),
|
||||
Site(name='Site 3', slug='site-3'),
|
||||
)
|
||||
Site.objects.bulk_create(sites)
|
||||
|
||||
# Simulate *creation* changelog records for two of the sites
|
||||
request_id = uuid.uuid4()
|
||||
objectchanges = (
|
||||
ObjectChange(
|
||||
changed_object_type=content_type,
|
||||
changed_object_id=sites[0].pk,
|
||||
action=ObjectChangeActionChoices.ACTION_CREATE,
|
||||
request_id=request_id
|
||||
),
|
||||
ObjectChange(
|
||||
changed_object_type=content_type,
|
||||
changed_object_id=sites[1].pk,
|
||||
action=ObjectChangeActionChoices.ACTION_CREATE,
|
||||
request_id=request_id
|
||||
),
|
||||
)
|
||||
ObjectChange.objects.bulk_create(objectchanges)
|
||||
|
||||
# Simulate *update* changelog records for two of the sites
|
||||
request_id = uuid.uuid4()
|
||||
objectchanges = (
|
||||
ObjectChange(
|
||||
changed_object_type=content_type,
|
||||
changed_object_id=sites[0].pk,
|
||||
action=ObjectChangeActionChoices.ACTION_UPDATE,
|
||||
request_id=request_id
|
||||
),
|
||||
ObjectChange(
|
||||
changed_object_type=content_type,
|
||||
changed_object_id=sites[1].pk,
|
||||
action=ObjectChangeActionChoices.ACTION_UPDATE,
|
||||
request_id=request_id
|
||||
),
|
||||
)
|
||||
ObjectChange.objects.bulk_create(objectchanges)
|
||||
|
||||
def test_created_by_request(self):
|
||||
request_id = ObjectChange.objects.filter(action=ObjectChangeActionChoices.ACTION_CREATE).first().request_id
|
||||
params = {'created_by_request': request_id}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
self.assertEqual(self.queryset.count(), 3)
|
||||
|
||||
def test_updated_by_request(self):
|
||||
request_id = ObjectChange.objects.filter(action=ObjectChangeActionChoices.ACTION_UPDATE).first().request_id
|
||||
params = {'updated_by_request': request_id}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
self.assertEqual(self.queryset.count(), 3)
|
||||
|
@ -7,9 +7,9 @@ from django_filters.exceptions import FieldLookupError
|
||||
from django_filters.utils import get_model_field, resolve_field
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from extras.choices import CustomFieldFilterLogicChoices
|
||||
from extras.choices import CustomFieldFilterLogicChoices, ObjectChangeActionChoices
|
||||
from extras.filters import TagFilter
|
||||
from extras.models import CustomField, SavedFilter
|
||||
from extras.models import CustomField, ObjectChange, SavedFilter
|
||||
from utilities.constants import (
|
||||
FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP,
|
||||
FILTER_NUMERIC_BASED_LOOKUP_MAP
|
||||
@ -231,6 +231,26 @@ class ChangeLoggedModelFilterSet(BaseFilterSet):
|
||||
"""
|
||||
created = filters.MultiValueDateTimeFilter()
|
||||
last_updated = filters.MultiValueDateTimeFilter()
|
||||
created_by_request = django_filters.UUIDFilter(
|
||||
method='filter_by_request'
|
||||
)
|
||||
updated_by_request = django_filters.UUIDFilter(
|
||||
method='filter_by_request'
|
||||
)
|
||||
|
||||
def filter_by_request(self, queryset, name, value):
|
||||
content_type = ContentType.objects.get_for_model(self.Meta.model)
|
||||
action = {
|
||||
'created_by_request': ObjectChangeActionChoices.ACTION_CREATE,
|
||||
'updated_by_request': ObjectChangeActionChoices.ACTION_UPDATE,
|
||||
}.get(name)
|
||||
request_id = value
|
||||
pks = ObjectChange.objects.filter(
|
||||
changed_object_type=content_type,
|
||||
action=action,
|
||||
request_id=request_id
|
||||
).values_list('changed_object_id', flat=True)
|
||||
return queryset.filter(pk__in=pks)
|
||||
|
||||
|
||||
class NetBoxModelFilterSet(ChangeLoggedModelFilterSet):
|
||||
|
Loading…
Reference in New Issue
Block a user