Fixes #19264: Support table configs on child object list views (#19284)

* Fixes #19264: Support table configs on child object list views

* Clear assigned table config when resetting the configuration
This commit is contained in:
Jeremy Stretch 2025-04-23 13:43:25 -04:00 committed by GitHub
parent dfd788c643
commit a83dfff736
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 37 additions and 21 deletions

View File

@ -7,7 +7,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRel
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError
from django.db import transaction, IntegrityError
from django.db.models import ManyToManyField, ProtectedError, Q, RestrictedError
from django.db.models import ManyToManyField, ProtectedError, RestrictedError
from django.db.models.fields.reverse_related import ManyToManyRel
from django.forms import ModelMultipleChoiceField, MultipleHiddenInput
from django.http import HttpResponse
@ -21,7 +21,7 @@ from mptt.models import MPTTModel
from core.models import ObjectType
from core.signals import clear_events
from extras.choices import CustomFieldUIEditableChoices
from extras.models import CustomField, ExportTemplate, TableConfig
from extras.models import CustomField, ExportTemplate
from utilities.error_handlers import handle_protectederror
from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fields
@ -29,6 +29,7 @@ from utilities.forms.bulk_import import BulkImportForm
from utilities.htmx import htmx_partial
from utilities.permissions import get_permission_for_model
from utilities.query import reapply_model_ordering
from utilities.tables import get_table_configs
from utilities.views import GetReturnURLMixin, get_viewname
from .base import BaseMultiObjectView
from .mixins import ActionsMixin, TableMixin
@ -140,15 +141,6 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
model = self.queryset.model
object_type = ObjectType.objects.get_for_model(model)
# If a TableConfig has been specified, apply it & update the user's saved preference
if tableconfig_id := request.GET.get('tableconfig_id'):
tableconfig = get_object_or_404(TableConfig, pk=tableconfig_id)
if request.user.is_authenticated:
table = self.table.__name__
request.user.config.set(f'tables.{table}.columns', tableconfig.columns)
request.user.config.set(f'tables.{table}.ordering', tableconfig.ordering, commit=True)
return redirect(request.path)
if self.filterset:
self.queryset = self.filterset(request.GET, self.queryset, request=request).qs
@ -184,14 +176,6 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
# Render the objects table
table = self.get_table(self.queryset, request, has_bulk_actions)
# Retrieve available configurations for the table
table_configs = TableConfig.objects.filter(
Q(shared=True) | Q(user=request.user if request.user.is_authenticated else None),
object_type=object_type,
table=table.name,
enabled=True,
)
# If this is an HTMX request, return only the rendered table HTML
if htmx_partial(request):
if request.GET.get('embedded', False):
@ -208,7 +192,7 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
context = {
'model': model,
'table': table,
'table_configs': table_configs,
'table_configs': get_table_configs(table, request.user),
'actions': actions,
'filter_form': self.filterset_form(request.GET) if self.filterset_form else None,
'prerequisite_model': get_prerequisite_model(self.queryset),

View File

@ -1,3 +1,6 @@
from django.shortcuts import get_object_or_404
from extras.models import TableConfig
from netbox.constants import DEFAULT_ACTION_PERMISSIONS
from utilities.permissions import get_permission_for_model
@ -47,6 +50,15 @@ class TableMixin:
request: The current request
bulk_actions: Render checkboxes for object selection
"""
# If a TableConfig has been specified, apply it & update the user's saved preference
if tableconfig_id := request.GET.get('tableconfig_id'):
tableconfig = get_object_or_404(TableConfig, pk=tableconfig_id)
if request.user.is_authenticated:
table = self.table.__name__
request.user.config.set(f'tables.{table}.columns', tableconfig.columns)
request.user.config.set(f'tables.{table}.ordering', tableconfig.ordering, commit=True)
table = self.table(data, user=request.user)
if 'pk' in table.base_columns and bulk_actions:
table.columns.show('pk')

View File

@ -20,6 +20,7 @@ from utilities.forms import ConfirmationForm, restrict_form_fields
from utilities.htmx import htmx_partial
from utilities.permissions import get_permission_for_model
from utilities.querydict import normalize_querydict, prepare_cloned_fields
from utilities.tables import get_table_configs
from utilities.views import GetReturnURLMixin, get_viewname
from .base import BaseObjectView
from .mixins import ActionsMixin, TableMixin
@ -156,6 +157,7 @@ class ObjectChildrenView(ObjectView, ActionsMixin, TableMixin):
'base_template': f'{instance._meta.app_label}/{instance._meta.model_name}.html',
'table': table,
'table_config': f'{table.name}_config',
'table_configs': get_table_configs(table, request.user),
'filter_form': self.filterset_form(request.GET) if self.filterset_form else None,
'actions': actions,
'tab': self.tab,

Binary file not shown.

Binary file not shown.

View File

@ -80,7 +80,8 @@ function handleSubmit(event: Event): void {
const toast = createToast('danger', 'Error Resetting Table Configuration', res.error);
toast.show();
} else {
location.reload();
// Strip any URL query parameters & reload the page
window.location.href = window.location.origin + window.location.pathname;
}
});
return;

View File

@ -1,9 +1,13 @@
from django.apps import apps
from django.db.models import Q
from django.utils.module_loading import import_string
from django.utils.translation import gettext_lazy as _
from core.models import ObjectType
from netbox.registry import registry
__all__ = (
'get_table_configs',
'get_table_for_model',
'get_table_ordering',
'linkify_phone',
@ -11,6 +15,19 @@ __all__ = (
)
def get_table_configs(table, user):
"""
Return any available TableConfigs applicable to the given table & user.
"""
TableConfig = apps.get_model('extras', 'TableConfig')
return TableConfig.objects.filter(
Q(shared=True) | Q(user=user if user.is_authenticated else None),
object_type=ObjectType.objects.get_for_model(table.Meta.model),
table=table.name,
enabled=True,
)
def get_table_for_model(model, name=None):
name = name or f'{model.__name__}Table'
try: