Просмотр исходного кода

Fixes: #18863 - Exempt MPTT-based models from centrally applying ordering on querysets (#18867)

bctiemann 11 месяцев назад
Родитель
Сommit
4f45328c77

+ 2 - 6
netbox/netbox/api/viewsets/__init__.py

@@ -12,6 +12,7 @@ from rest_framework.viewsets import GenericViewSet
 
 from utilities.api import get_annotations_for_serializer, get_prefetches_for_serializer
 from utilities.exceptions import AbortRequest
+from utilities.query import reapply_model_ordering
 from . import mixins
 
 __all__ = (
@@ -122,13 +123,8 @@ class NetBoxModelViewSet(
         return obj
 
     def get_queryset(self):
-        """
-        Reapply model-level ordering in case it has been lost through .annotate().
-        https://code.djangoproject.com/ticket/32811
-        """
         qs = super().get_queryset()
-        ordering = qs.model._meta.ordering
-        return qs.order_by(*ordering)
+        return reapply_model_ordering(qs)
 
     def get_serializer(self, *args, **kwargs):
         # If a list of objects has been provided, initialize the serializer with many=True

+ 2 - 6
netbox/netbox/views/generic/bulk_views.py

@@ -28,6 +28,7 @@ from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fiel
 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.views import GetReturnURLMixin, get_viewname
 from .base import BaseMultiObjectView
 from .mixins import ActionsMixin, TableMixin
@@ -126,13 +127,8 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
     #
 
     def get_queryset(self, request):
-        """
-        Reapply model-level ordering in case it has been lost through .annotate().
-        https://code.djangoproject.com/ticket/32811
-        """
         qs = super().get_queryset(request)
-        ordering = qs.model._meta.ordering
-        return qs.order_by(*ordering)
+        return reapply_model_ordering(qs)
 
     def get(self, request):
         """

+ 16 - 1
netbox/utilities/query.py

@@ -1,9 +1,12 @@
-from django.db.models import Count, OuterRef, Subquery
+from django.db.models import Count, OuterRef, Subquery, QuerySet
 from django.db.models.functions import Coalesce
 
+from utilities.mptt import TreeManager
+
 __all__ = (
     'count_related',
     'dict_to_filter_params',
+    'reapply_model_ordering',
 )
 
 
@@ -54,3 +57,15 @@ def dict_to_filter_params(d, prefix=''):
         else:
             params[k] = val
     return params
+
+
+def reapply_model_ordering(queryset: QuerySet) -> QuerySet:
+    """
+    Reapply model-level ordering in case it has been lost through .annotate().
+    https://code.djangoproject.com/ticket/32811
+    """
+    # MPTT-based models are exempt from this; use caution when annotating querysets of these models
+    if any(isinstance(manager, TreeManager) for manager in queryset.model._meta.local_managers):
+        return queryset
+    ordering = queryset.model._meta.ordering
+    return queryset.order_by(*ordering)