Merge pull request #9631 from jumpserver/pr@dev@perf_ordering

perf: 优化排序
pull/9632/head^2
老广 2023-02-20 13:41:30 +08:00 committed by GitHub
commit 5058d8158d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 142 additions and 63 deletions

View File

@ -20,7 +20,6 @@ class AccountBackupPlanViewSet(OrgBulkModelViewSet):
model = AccountBackupAutomation model = AccountBackupAutomation
filter_fields = ('name',) filter_fields = ('name',)
search_fields = filter_fields search_fields = filter_fields
ordering_fields = ('name',)
ordering = ('name',) ordering = ('name',)
serializer_class = serializers.AccountBackupSerializer serializer_class = serializers.AccountBackupSerializer

View File

@ -25,7 +25,6 @@ class ChangeSecretAutomationViewSet(OrgBulkModelViewSet):
model = ChangeSecretAutomation model = ChangeSecretAutomation
filter_fields = ('name', 'secret_type', 'secret_strategy') filter_fields = ('name', 'secret_type', 'secret_strategy')
search_fields = filter_fields search_fields = filter_fields
ordering_fields = ('name',)
serializer_class = serializers.ChangeSecretAutomationSerializer serializer_class = serializers.ChangeSecretAutomationSerializer

View File

@ -15,7 +15,6 @@ class GatherAccountsAutomationViewSet(OrgBulkModelViewSet):
model = GatherAccountsAutomation model = GatherAccountsAutomation
filter_fields = ('name',) filter_fields = ('name',)
search_fields = filter_fields search_fields = filter_fields
ordering_fields = ('name',)
serializer_class = serializers.GatherAccountAutomationSerializer serializer_class = serializers.GatherAccountAutomationSerializer

View File

@ -22,7 +22,6 @@ class PushAccountAutomationViewSet(OrgBulkModelViewSet):
model = PushAccountAutomation model = PushAccountAutomation
filter_fields = ('name', 'secret_type', 'secret_strategy') filter_fields = ('name', 'secret_type', 'secret_strategy')
search_fields = filter_fields search_fields = filter_fields
ordering_fields = ('name',)
serializer_class = serializers.PushAccountAutomationSerializer serializer_class = serializers.PushAccountAutomationSerializer

View File

@ -95,7 +95,6 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
model = Asset model = Asset
filterset_class = AssetFilterSet filterset_class = AssetFilterSet
search_fields = ("name", "address") search_fields = ("name", "address")
ordering_fields = ("name", "address", "connectivity")
ordering = ("name", "connectivity") ordering = ("name", "connectivity")
serializer_classes = ( serializer_classes = (
("default", serializers.AssetSerializer), ("default", serializers.AssetSerializer),

View File

@ -3,8 +3,9 @@ from django.utils.translation import ugettext as _
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from rest_framework.views import APIView, Response from rest_framework.views import APIView, Response
from common.utils import get_logger
from assets.tasks import test_gateways_connectivity_manual from assets.tasks import test_gateways_connectivity_manual
from common.utils import get_logger
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from .asset import HostViewSet from .asset import HostViewSet
from .. import serializers from .. import serializers
@ -18,14 +19,12 @@ class DomainViewSet(OrgBulkModelViewSet):
model = Domain model = Domain
filterset_fields = ("name",) filterset_fields = ("name",)
search_fields = filterset_fields search_fields = filterset_fields
serializer_class = serializers.DomainSerializer
ordering_fields = ('name',)
ordering = ('name',) ordering = ('name',)
def get_serializer_class(self): def get_serializer_class(self):
if self.request.query_params.get('gateway'): if self.request.query_params.get('gateway'):
return serializers.DomainWithGatewaySerializer return serializers.DomainWithGatewaySerializer
return super().get_serializer_class() return serializers.DomainSerializer
class GatewayViewSet(HostViewSet): class GatewayViewSet(HostViewSet):

View File

@ -0,0 +1,38 @@
# Generated by Django 3.2.14 on 2023-02-20 02:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0109_alter_asset_options'),
]
operations = [
migrations.AddField(
model_name='platform',
name='created_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
),
migrations.AddField(
model_name='platform',
name='date_created',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created'),
),
migrations.AddField(
model_name='platform',
name='date_updated',
field=models.DateTimeField(auto_now=True, verbose_name='Date updated'),
),
migrations.AddField(
model_name='platform',
name='updated_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by'),
),
migrations.AlterField(
model_name='platform',
name='comment',
field=models.TextField(blank=True, default='', verbose_name='Comment'),
),
]

View File

@ -4,6 +4,7 @@ from django.utils.translation import gettext_lazy as _
from assets.const import AllTypes from assets.const import AllTypes
from assets.const import Protocol from assets.const import Protocol
from common.db.fields import JsonDictTextField from common.db.fields import JsonDictTextField
from common.db.models import JMSBaseModel
__all__ = ['Platform', 'PlatformProtocol', 'PlatformAutomation'] __all__ = ['Platform', 'PlatformProtocol', 'PlatformAutomation']
@ -61,7 +62,7 @@ class PlatformAutomation(models.Model):
) )
class Platform(models.Model): class Platform(JMSBaseModel):
""" """
对资产提供 约束和默认值 对资产提供 约束和默认值
对资产进行抽象 对资产进行抽象
@ -71,12 +72,12 @@ class Platform(models.Model):
utf8 = 'utf-8', 'UTF-8' utf8 = 'utf-8', 'UTF-8'
gbk = 'gbk', 'GBK' gbk = 'gbk', 'GBK'
id = models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
name = models.SlugField(verbose_name=_("Name"), unique=True, allow_unicode=True) name = models.SlugField(verbose_name=_("Name"), unique=True, allow_unicode=True)
category = models.CharField(default='host', max_length=32, verbose_name=_("Category")) category = models.CharField(default='host', max_length=32, verbose_name=_("Category"))
type = models.CharField(max_length=32, default='linux', verbose_name=_("Type")) type = models.CharField(max_length=32, default='linux', verbose_name=_("Type"))
meta = JsonDictTextField(blank=True, null=True, verbose_name=_("Meta")) meta = JsonDictTextField(blank=True, null=True, verbose_name=_("Meta"))
internal = models.BooleanField(default=False, verbose_name=_("Internal")) internal = models.BooleanField(default=False, verbose_name=_("Internal"))
comment = models.TextField(blank=True, null=True, verbose_name=_("Comment"))
# 资产有关的 # 资产有关的
charset = models.CharField( charset = models.CharField(
default=CharsetChoices.utf8, choices=CharsetChoices.choices, max_length=8, verbose_name=_("Charset") default=CharsetChoices.utf8, choices=CharsetChoices.choices, max_length=8, verbose_name=_("Charset")

View File

@ -106,12 +106,13 @@ class PlatformSerializer(WritableNestedModelSerializer):
fields_small = fields_mini + [ fields_small = fields_mini + [
"category", "type", "charset", "category", "type", "charset",
] ]
fields = fields_small + [ fields_other = [
"protocols", 'date_created', 'date_updated', 'created_by', 'updated_by',
"domain_enabled", "su_enabled",
"su_method", "automation",
"comment",
] ]
fields = fields_small + [
"protocols", "domain_enabled", "su_enabled",
"su_method", "automation", "comment",
] + fields_other
extra_kwargs = { extra_kwargs = {
"su_enabled": {"label": _('Su enabled')}, "su_enabled": {"label": _('Su enabled')},
"domain_enabled": {"label": _('Domain enabled')}, "domain_enabled": {"label": _('Domain enabled')},

View File

@ -1,13 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import logging
from itertools import chain from itertools import chain
from django.db import models
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
from common.drf.filters import IDSpmFilter, CustomFilter, IDInFilter from common.drf.filters import IDSpmFilter, CustomFilter, IDInFilter
__all__ = ['ExtraFilterFieldsMixin', 'OrderingFielderFieldsMixin']
__all__ = ['ExtraFilterFieldsMixin']
class ExtraFilterFieldsMixin: class ExtraFilterFieldsMixin:
@ -33,3 +34,55 @@ class ExtraFilterFieldsMixin:
for backend in self.get_filter_backends(): for backend in self.get_filter_backends():
queryset = backend().filter_queryset(self.request, queryset, self) queryset = backend().filter_queryset(self.request, queryset, self)
return queryset return queryset
class OrderingFielderFieldsMixin:
"""
额外的 api ordering
"""
ordering_fields = None
extra_ordering_fields = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ordering_fields = self._get_ordering_fields()
def _get_ordering_fields(self):
if isinstance(self.__class__.ordering_fields, (list, tuple)):
return self.__class__.ordering_fields
try:
valid_fields = self.get_valid_ordering_fields()
except Exception as e:
logging.debug('get_valid_ordering_fields error: %s' % e)
valid_fields = []
fields = list(chain(
valid_fields,
self.extra_ordering_fields
))
return fields
def get_valid_ordering_fields(self):
if getattr(self, 'model', None):
model = self.model
elif getattr(self, 'queryset', None):
model = self.queryset.model
else:
queryset = self.get_queryset()
model = queryset.model
if not model:
return []
excludes_fields = (
models.UUIDField, models.Model, models.ForeignKey,
models.FileField, models.JSONField, models.ManyToManyField,
models.DurationField,
)
valid_fields = []
for field in model._meta.fields:
if isinstance(field, excludes_fields):
continue
valid_fields.append(field.name)
return valid_fields

View File

@ -7,7 +7,7 @@ from django.db.models.signals import m2m_changed
from rest_framework.response import Response from rest_framework.response import Response
from .action import RenderToJsonMixin from .action import RenderToJsonMixin
from .filter import ExtraFilterFieldsMixin from .filter import ExtraFilterFieldsMixin, OrderingFielderFieldsMixin
from .serializer import SerializerMixin from .serializer import SerializerMixin
__all__ = [ __all__ = [
@ -98,7 +98,6 @@ class QuerySetMixin:
return queryset return queryset
class CommonApiMixin(SerializerMixin, ExtraFilterFieldsMixin, class CommonApiMixin(SerializerMixin, ExtraFilterFieldsMixin, OrderingFielderFieldsMixin,
QuerySetMixin, RenderToJsonMixin, QuerySetMixin, RenderToJsonMixin, PaginatedResponseMixin):
PaginatedResponseMixin):
pass pass

View File

@ -1,18 +1,20 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from rest_framework import filters import logging
from rest_framework.fields import DateTimeField
from rest_framework.serializers import ValidationError
from rest_framework.compat import coreapi, coreschema
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django_filters import rest_framework as drf_filters from django_filters import rest_framework as drf_filters
import logging from rest_framework import filters
from rest_framework.compat import coreapi, coreschema
from rest_framework.fields import DateTimeField
from rest_framework.serializers import ValidationError
from common import const from common import const
__all__ = [ __all__ = [
"DatetimeRangeFilter", "IDSpmFilter", 'IDInFilter', "CustomFilter", "DatetimeRangeFilter", "IDSpmFilter",
'IDInFilter', "CustomFilter",
"BaseFilterSet" "BaseFilterSet"
] ]

View File

@ -1,9 +1,9 @@
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals from __future__ import unicode_literals
from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django_celery_beat.models import PeriodicTask from django_celery_beat.models import PeriodicTask
from rest_framework import serializers
__all__ = [ __all__ = [
'CeleryResultSerializer', 'CeleryTaskExecutionSerializer', 'CeleryResultSerializer', 'CeleryTaskExecutionSerializer',
@ -41,7 +41,7 @@ class CeleryTaskExecutionSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = CeleryTaskExecution model = CeleryTaskExecution
fields = [ fields = [
"id", "name", "args", "kwargs", "time_cost", "timedelta", "is_success", "is_finished", "date_published", "id", "name", "args", "kwargs", "time_cost", "timedelta",
"date_start", "is_success", "is_finished", "date_published",
"date_finished" "date_start", "date_finished"
] ]

View File

@ -1,20 +1,20 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.utils.translation import ugettext as _
from django.conf import settings from django.conf import settings
from rest_framework_bulk import BulkModelViewSet from django.utils.translation import ugettext as _
from rest_framework.generics import RetrieveAPIView
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
from rest_framework.generics import RetrieveAPIView
from common.utils import get_logger
from common.permissions import IsValidUser
from users.models import User, UserGroup
from assets.models import ( from assets.models import (
Asset, Domain, Label, Node, Asset, Domain, Label, Node,
) )
from perms.models import AssetPermission from common.api import JMSBulkModelViewSet
from common.permissions import IsValidUser
from common.utils import get_logger
from orgs.utils import current_org, tmp_to_root_org from orgs.utils import current_org, tmp_to_root_org
from perms.models import AssetPermission
from users.models import User, UserGroup
from .models import Organization from .models import Organization
from .serializers import ( from .serializers import (
OrgSerializer, CurrentOrgSerializer OrgSerializer, CurrentOrgSerializer
@ -29,12 +29,11 @@ org_related_models = [
] ]
class OrgViewSet(BulkModelViewSet): class OrgViewSet(JMSBulkModelViewSet):
filterset_fields = ('name',) filterset_fields = ('name',)
search_fields = ('name', 'comment') search_fields = ('name', 'comment')
queryset = Organization.objects.all() queryset = Organization.objects.all()
serializer_class = OrgSerializer serializer_class = OrgSerializer
ordering_fields = ('name',)
ordering = ('name',) ordering = ('name',)
def get_serializer_class(self): def get_serializer_class(self):

View File

@ -16,5 +16,4 @@ class AssetPermissionViewSet(OrgBulkModelViewSet):
serializer_class = serializers.AssetPermissionSerializer serializer_class = serializers.AssetPermissionSerializer
filterset_class = AssetPermissionFilter filterset_class = AssetPermissionFilter
search_fields = ('name',) search_fields = ('name',)
ordering_fields = ('name',)
ordering = ('name',) ordering = ('name',)

View File

@ -1,19 +1,18 @@
import abc import abc
from rest_framework.generics import ListAPIView from rest_framework.generics import ListAPIView
from assets.models import Asset, Node
from assets.api.asset.asset import AssetFilterSet from assets.api.asset.asset import AssetFilterSet
from assets.models import Asset, Node
from common.utils import get_logger, lazyproperty
from perms import serializers from perms import serializers
from perms.pagination import AllPermedAssetPagination from perms.pagination import AllPermedAssetPagination
from perms.pagination import NodePermedAssetPagination from perms.pagination import NodePermedAssetPagination
from perms.utils import UserPermAssetUtil from perms.utils import UserPermAssetUtil
from common.utils import get_logger, lazyproperty
from .mixin import ( from .mixin import (
SelfOrPKUserMixin SelfOrPKUserMixin
) )
__all__ = [ __all__ = [
'UserAllPermedAssetsApi', 'UserAllPermedAssetsApi',
'UserDirectPermedAssetsApi', 'UserDirectPermedAssetsApi',
@ -26,8 +25,8 @@ logger = get_logger(__name__)
class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ListAPIView): class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ListAPIView):
ordering = ('name',) ordering = ('name',)
ordering_fields = ("name", "address")
search_fields = ('name', 'address', 'comment') search_fields = ('name', 'address', 'comment')
ordering_fields = ("name", "address")
filterset_class = AssetFilterSet filterset_class = AssetFilterSet
serializer_class = serializers.AssetPermedSerializer serializer_class = serializers.AssetPermedSerializer
only_fields = serializers.AssetPermedSerializer.Meta.only_fields only_fields = serializers.AssetPermedSerializer.Meta.only_fields

View File

@ -1,22 +1,23 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import logging import logging
from rest_framework.views import APIView, Response
from rest_framework_bulk import BulkModelViewSet
from rest_framework import status from rest_framework import status
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView, Response
from common.api import JMSBulkModelViewSet
from common.utils import get_object_or_none from common.utils import get_object_or_none
from orgs.utils import tmp_to_root_org from orgs.utils import tmp_to_root_org
from terminal.models import Session, Task
from terminal import serializers from terminal import serializers
from terminal.models import Session, Task
from terminal.utils import is_session_approver from terminal.utils import is_session_approver
__all__ = ['TaskViewSet', 'KillSessionAPI', 'KillSessionForTicketAPI'] __all__ = ['TaskViewSet', 'KillSessionAPI', 'KillSessionForTicketAPI']
logger = logging.getLogger(__file__) logger = logging.getLogger(__file__)
class TaskViewSet(BulkModelViewSet): class TaskViewSet(JMSBulkModelViewSet):
queryset = Task.objects.all() queryset = Task.objects.all()
serializer_class = serializers.TaskSerializer serializer_class = serializers.TaskSerializer
filterset_fields = ('is_finished',) filterset_fields = ('is_finished',)
@ -51,7 +52,7 @@ class KillSessionAPI(APIView):
class KillSessionForTicketAPI(APIView): class KillSessionForTicketAPI(APIView):
permission_classes = (IsAuthenticated, ) permission_classes = (IsAuthenticated,)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
session_ids = request.data session_ids = request.data

View File

@ -35,10 +35,6 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
search_fields = [ search_fields = [
'title', 'type', 'status' 'title', 'type', 'status'
] ]
ordering_fields = (
'title', 'status', 'state', 'action_display',
'date_created', 'serial_num',
)
ordering = ('-date_created',) ordering = ('-date_created',)
rbac_perms = { rbac_perms = {
'open': 'tickets.view_ticket', 'open': 'tickets.view_ticket',

View File

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from ..serializers import UserGroupSerializer
from ..models import UserGroup
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from ..models import UserGroup
from ..serializers import UserGroupSerializer
__all__ = ['UserGroupViewSet'] __all__ = ['UserGroupViewSet']
@ -14,5 +13,4 @@ class UserGroupViewSet(OrgBulkModelViewSet):
filterset_fields = ("name",) filterset_fields = ("name",)
search_fields = filterset_fields search_fields = filterset_fields
serializer_class = UserGroupSerializer serializer_class = UserGroupSerializer
ordering_fields = ('name', ) ordering = ('name',)
ordering = ('name', )

View File

@ -39,7 +39,6 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, SuggestionMixin, BulkModelV
'suggestion': MiniUserSerializer, 'suggestion': MiniUserSerializer,
'invite': InviteSerializer, 'invite': InviteSerializer,
} }
ordering_fields = ('name',)
ordering = ('name',) ordering = ('name',)
rbac_perms = { rbac_perms = {
'match': 'users.match_user', 'match': 'users.match_user',