From 0c7de507083e9fbca1d6966234baccb2c85f397f Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 7 Dec 2022 18:58:57 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20display=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/models/label.py | 5 + apps/assets/serializers/label.py | 25 ++-- apps/assets/serializers/platform.py | 43 ++----- apps/audits/serializers.py | 69 ++--------- apps/common/drf/serializers/mixin.py | 22 +++- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/rbac/serializers/role.py | 7 +- apps/terminal/backends/command/serializers.py | 6 - apps/terminal/serializers/session.py | 10 +- apps/users/serializers/user.py | 114 ++++-------------- 11 files changed, 89 insertions(+), 220 deletions(-) diff --git a/apps/assets/models/label.py b/apps/assets/models/label.py index afad1f069..2e0ff92ee 100644 --- a/apps/assets/models/label.py +++ b/apps/assets/models/label.py @@ -4,6 +4,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from common.utils import lazyproperty from orgs.mixins.models import JMSOrgBaseModel @@ -27,6 +28,10 @@ class Label(JMSOrgBaseModel): for name in names: yield name, cls.objects.filter(name=name) + @lazyproperty + def asset_count(self): + return self.assets.count() + def __str__(self): return "{}:{}".format(self.name, self.value) diff --git a/apps/assets/serializers/label.py b/apps/assets/serializers/label.py index 450b13a44..6992f4e8d 100644 --- a/apps/assets/serializers/label.py +++ b/apps/assets/serializers/label.py @@ -1,25 +1,22 @@ # -*- coding: utf-8 -*- # -from rest_framework import serializers +from django.db.models import Count from django.utils.translation import ugettext_lazy as _ +from rest_framework import serializers from orgs.mixins.serializers import BulkOrgResourceModelSerializer - from ..models import Label class LabelSerializer(BulkOrgResourceModelSerializer): - asset_count = serializers.SerializerMethodField(label=_("Assets amount")) - category_display = serializers.ReadOnlyField(source='get_category_display', label=_('Category display')) + asset_count = serializers.ReadOnlyField(label=_("Assets amount")) class Meta: model = Label fields_mini = ['id', 'name'] fields_small = fields_mini + [ - 'value', 'category', 'category_display', - 'is_active', - 'date_created', - 'comment', + 'value', 'category', 'is_active', + 'date_created', 'comment', ] fields_m2m = ['asset_count', 'assets'] fields = fields_small + fields_m2m @@ -30,14 +27,10 @@ class LabelSerializer(BulkOrgResourceModelSerializer): 'assets': {'required': False, 'label': _('Asset')} } - @staticmethod - def get_asset_count(obj): - return obj.assets.count() - - def get_field_names(self, declared_fields, info): - fields = super().get_field_names(declared_fields, info) - fields.extend(['get_category_display']) - return fields + @classmethod + def setup_eager_loading(cls, queryset): + queryset = queryset.annotate(asset_count=Count('assets')) + return queryset class LabelDistinctSerializer(BulkOrgResourceModelSerializer): diff --git a/apps/assets/serializers/platform.py b/apps/assets/serializers/platform.py index 6f7458543..297896915 100644 --- a/apps/assets/serializers/platform.py +++ b/apps/assets/serializers/platform.py @@ -42,20 +42,13 @@ class PlatformAutomationSerializer(serializers.ModelSerializer): model = PlatformAutomation fields = [ "id", - "ansible_enabled", - "ansible_config", - "ping_enabled", - "ping_method", - "gather_facts_enabled", - "gather_facts_method", - "push_account_enabled", - "push_account_method", - "change_secret_enabled", - "change_secret_method", - "verify_account_enabled", - "verify_account_method", - "gather_accounts_enabled", - "gather_accounts_method", + "ansible_enabled", "ansible_config", + "ping_enabled", "ping_method", + "gather_facts_enabled", "gather_facts_method", + "push_account_enabled", "push_account_method", + "change_secret_enabled", "change_secret_method", + "verify_account_enabled", "verify_account_method", + "gather_accounts_enabled", "gather_accounts_method", ] extra_kwargs = { "ping_enabled": {"label": "启用资产探测"}, @@ -80,13 +73,8 @@ class PlatformProtocolsSerializer(serializers.ModelSerializer): class Meta: model = PlatformProtocol fields = [ - "id", - "name", - "port", - "primary", - "default", - "required", - "secret_types", + "id", "name", "port", "primary", + "default", "required", "secret_types", "setting", ] @@ -112,17 +100,12 @@ class PlatformSerializer(WritableNestedModelSerializer): model = Platform fields_mini = ["id", "name", "internal"] fields_small = fields_mini + [ - "category", - "type", - "charset", + "category", "type", "charset", ] fields = fields_small + [ - "protocols_enabled", - "protocols", - "domain_enabled", - "su_enabled", - "su_method", - "automation", + "protocols_enabled", "protocols", + "domain_enabled", "su_enabled", + "su_method", "automation", "comment", ] extra_kwargs = { diff --git a/apps/audits/serializers.py b/apps/audits/serializers.py index 10e5a7f16..3b9772106 100644 --- a/apps/audits/serializers.py +++ b/apps/audits/serializers.py @@ -44,18 +44,11 @@ class UserLoginLogSerializer(serializers.ModelSerializer): model = models.UserLoginLog fields_mini = ["id"] fields_small = fields_mini + [ - "username", - "type", - "ip", - "city", - "user_agent", - "mfa", - "reason", - "reason_display", - "backend", - "backend_display", - "status", - "datetime", + "username", "type", "ip", + "city", "user_agent", "mfa", + "reason", "reason_display", + "backend", "backend_display", + "status", "datetime", ] fields = fields_small extra_kwargs = { @@ -78,14 +71,9 @@ class OperateLogSerializer(serializers.ModelSerializer): model = models.OperateLog fields_mini = ["id"] fields_small = fields_mini + [ - "user", - "action", - "resource_type", - "resource_type_display", - "resource", - "remote_addr", - "datetime", - "org_id", + "user", "action", "resource_type", + "resource_type_display", "resource", + "remote_addr", "datetime", "org_id", ] fields = fields_small extra_kwargs = {"resource_type_display": {"label": _("Resource Type")}} @@ -101,44 +89,3 @@ class SessionAuditSerializer(serializers.ModelSerializer): class Meta: model = Session fields = "__all__" - - -# -# class CommandExecutionSerializer(serializers.ModelSerializer): -# is_success = serializers.BooleanField(read_only=True, label=_('Is success')) -# hosts_display = serializers.ListSerializer( -# child=serializers.CharField(), source='hosts', read_only=True, label=_('Hosts display') -# ) -# -# class Meta: -# model = CommandExecution -# fields_mini = ['id'] -# fields_small = fields_mini + [ -# 'command', 'is_finished', 'user', -# 'date_start', 'result', 'is_success', 'org_id' -# ] -# fields = fields_small + ['hosts', 'hosts_display', 'user_display'] -# extra_kwargs = { -# 'result': {'label': _('Result')}, # model 上的方法,只能在这修改 -# 'is_success': {'label': _('Is success')}, -# 'hosts': {'label': _('Hosts')}, # 外键,会生成 sql。不在 model 上修改 -# 'user': {'label': _('User')}, -# 'user_display': {'label': _('User display')}, -# } -# -# @classmethod -# def setup_eager_loading(cls, queryset): -# """ Perform necessary eager loading of data. """ -# queryset = queryset.prefetch_related('user', 'hosts') -# return queryset -# -# -# class CommandExecutionHostsRelationSerializer(BulkSerializerMixin, serializers.ModelSerializer): -# asset_display = serializers.ReadOnlyField() -# commandexecution_display = serializers.ReadOnlyField() -# -# class Meta: -# model = CommandExecution.hosts.through -# fields = [ -# 'id', 'asset', 'asset_display', 'commandexecution', 'commandexecution_display' -# ] diff --git a/apps/common/drf/serializers/mixin.py b/apps/common/drf/serializers/mixin.py index b0cbee27e..8d59fab1d 100644 --- a/apps/common/drf/serializers/mixin.py +++ b/apps/common/drf/serializers/mixin.py @@ -1,16 +1,15 @@ from collections import Iterable -from django.db.models import NOT_PROVIDED from django.core.exceptions import ObjectDoesNotExist -from rest_framework.utils import html +from django.db.models import NOT_PROVIDED from rest_framework import serializers -from rest_framework.settings import api_settings from rest_framework.exceptions import ValidationError from rest_framework.fields import SkipField, empty +from rest_framework.settings import api_settings +from rest_framework.utils import html from common.drf.fields import EncryptedField -from common.utils import lazyproperty - +from ..fields import LabeledChoiceField, ObjectRelatedField __all__ = [ 'BulkSerializerMixin', 'BulkListSerializerMixin', @@ -43,6 +42,7 @@ class BulkSerializerMixin(object): Become rest_framework_bulk not support uuid as a primary key so rewrite it. https://github.com/miki725/django-rest-framework-bulk/issues/66 """ + def to_internal_value(self, data): from rest_framework_bulk import BulkListSerializer ret = super(BulkSerializerMixin, self).to_internal_value(data) @@ -308,7 +308,12 @@ class DynamicFieldsMixin: self.fields.pop(field, None) -class CommonSerializerMixin(DynamicFieldsMixin, DefaultValueFieldsMixin): +class RelatedModelSerializerMixin: + serializer_related_field = ObjectRelatedField + serializer_choice_field = LabeledChoiceField + + +class SomeFieldsMixin: instance: None initial_data: dict common_fields = ( @@ -342,5 +347,10 @@ class CommonSerializerMixin(DynamicFieldsMixin, DefaultValueFieldsMixin): return primary_names + common_names +class CommonSerializerMixin(DynamicFieldsMixin, RelatedModelSerializerMixin, + SomeFieldsMixin, DefaultValueFieldsMixin): + pass + + class CommonBulkSerializerMixin(BulkSerializerMixin, CommonSerializerMixin): pass diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 8622a74d1..6cbc3b8ea 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03b1fcb75dae7e070f662f2ad554774d51311d2561367f5d28addc3b14899195 -size 119767 +oid sha256:5c366d6b10c4ce62bd8ed7c69ecaec5533f1a178b3cc7db4e6008769a6c8bb1f +size 119897 diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 0fc454c7f..1318974aa 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6bd3c45b4301a45fa1b110716b3ea78bcbb53a2913f707ab754882df061256cc -size 98368 +oid sha256:9f0b10566b4d35accd3a8766b14d6903243d93c5d7c55b208d930a189e590f2f +size 106125 diff --git a/apps/rbac/serializers/role.py b/apps/rbac/serializers/role.py index 6070fc8dc..140a01401 100644 --- a/apps/rbac/serializers/role.py +++ b/apps/rbac/serializers/role.py @@ -1,6 +1,7 @@ -from rest_framework import serializers from django.utils.translation import ugettext_lazy as _ +from rest_framework import serializers +from common.drf.fields import LabeledChoiceField from users.models import User from ..models import Role @@ -8,13 +9,13 @@ __all__ = ['RoleSerializer', 'RoleUserSerializer'] class RoleSerializer(serializers.ModelSerializer): - scope_display = serializers.ReadOnlyField(source='get_scope_display', label=_('Scope display')) + scope = LabeledChoiceField(choices=Role.Scope.choices, label=_("Scope")) class Meta: model = Role fields_mini = ['id', 'name', 'display_name', 'scope'] read_only_fields = [ - 'users_amount', 'builtin', 'scope_display', + 'users_amount', 'builtin', 'date_created', 'date_updated', 'created_by', 'updated_by', ] diff --git a/apps/terminal/backends/command/serializers.py b/apps/terminal/backends/command/serializers.py index ccf6984b8..e799f92f2 100644 --- a/apps/terminal/backends/command/serializers.py +++ b/apps/terminal/backends/command/serializers.py @@ -36,16 +36,10 @@ class SessionCommandSerializer(SimpleSessionCommandSerializer): # 限制 64 字符,不能直接迁移成 128 字符,命令表数据量会比较大 account = serializers.CharField(label=_("Account ")) output = serializers.CharField(max_length=2048, allow_blank=True, label=_("Output")) - risk_level_display = serializers.SerializerMethodField(label=_('Risk level display')) timestamp = serializers.IntegerField(label=_('Timestamp')) timestamp_display = serializers.DateTimeField(read_only=True, label=_('Datetime')) remote_addr = serializers.CharField(read_only=True, label=_('Remote Address')) - @staticmethod - def get_risk_level_display(obj): - risk_mapper = dict(AbstractSessionCommand.RISK_LEVEL_CHOICES) - return risk_mapper.get(obj.risk_level) - def validate_account(self, value): if len(value) > 64: value = pretty_string(value, 64) diff --git a/apps/terminal/serializers/session.py b/apps/terminal/serializers/session.py index 148217306..b8ec7bd69 100644 --- a/apps/terminal/serializers/session.py +++ b/apps/terminal/serializers/session.py @@ -1,9 +1,8 @@ +from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers -from django.utils.translation import ugettext_lazy as _ -from orgs.mixins.serializers import BulkOrgResourceModelSerializer - from assets.const import Protocol +from orgs.mixins.serializers import BulkOrgResourceModelSerializer from ..models import Session __all__ = [ @@ -14,7 +13,6 @@ __all__ = [ class SessionSerializer(BulkOrgResourceModelSerializer): org_id = serializers.CharField(allow_blank=True) - terminal_display = serializers.CharField(read_only=True, label=_('Terminal display')) protocol = serializers.ChoiceField(choices=Protocol.choices, label=_("Protocol")) class Meta: @@ -22,11 +20,11 @@ class SessionSerializer(BulkOrgResourceModelSerializer): fields_mini = ["id"] fields_small = fields_mini + [ "user", "asset", "user_id", "asset_id", 'account', "protocol", - "login_from", "login_from_display", "remote_addr", "is_success", + "login_from", "remote_addr", "is_success", "is_finished", "has_replay", "date_start", "date_end", ] fields_fk = ["terminal", ] - fields_custom = ["can_replay", "can_join", "can_terminate", 'terminal_display'] + fields_custom = ["can_replay", "can_join", "can_terminate"] fields = fields_small + fields_fk + fields_custom extra_kwargs = { "protocol": {'label': _('Protocol')}, diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index d84a7baa0..be083a322 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -1,18 +1,19 @@ # -*- coding: utf-8 -*- # from functools import partial + from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers +from common.drf.fields import EncryptedField, ObjectRelatedField, LabeledChoiceField from common.drf.serializers import CommonBulkSerializerMixin -from common.validators import PhoneValidator from common.utils import pretty_string, get_logger -from common.drf.fields import EncryptedField +from common.validators import PhoneValidator from rbac.builtin import BuiltinRole -from rbac.permissions import RBACPermission from rbac.models import OrgRoleBinding, SystemRoleBinding, Role -from ..models import User +from rbac.permissions import RBACPermission from ..const import PasswordStrategy +from ..models import User __all__ = [ "UserSerializer", @@ -25,19 +26,8 @@ logger = get_logger(__file__) class RolesSerializerMixin(serializers.Serializer): - system_roles = serializers.ManyRelatedField( - child_relation=serializers.PrimaryKeyRelatedField(queryset=Role.system_roles), - label=_("System roles"), - ) - org_roles = serializers.ManyRelatedField( - required=False, - child_relation=serializers.PrimaryKeyRelatedField(queryset=Role.org_roles), - label=_("Org roles"), - ) - system_roles_display = serializers.SerializerMethodField( - label=_("System roles display") - ) - org_roles_display = serializers.SerializerMethodField(label=_("Org roles display")) + system_roles = ObjectRelatedField(queryset=Role.system_roles, label=_("System roles"), many=True) + org_roles = ObjectRelatedField(queryset=Role.org_roles, label=_("Org roles"), many=True) @staticmethod def get_system_roles_display(user): @@ -60,8 +50,8 @@ class RolesSerializerMixin(serializers.Serializer): if action in ("partial_bulk_update", "bulk_update", "partial_update", "update"): action = "create" model_cls_field_mapper = { - SystemRoleBinding: ["system_roles", "system_roles_display"], - OrgRoleBinding: ["org_roles", "system_roles_display"], + SystemRoleBinding: ["system_roles"], + OrgRoleBinding: ["org_roles"], } for model_cls, fields_names in model_cls_field_mapper.items(): @@ -79,10 +69,8 @@ class RolesSerializerMixin(serializers.Serializer): return fields -class UserSerializer( - RolesSerializerMixin, CommonBulkSerializerMixin, serializers.ModelSerializer -): - password_strategy = serializers.ChoiceField( +class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, serializers.ModelSerializer): + password_strategy = LabeledChoiceField( choices=PasswordStrategy.choices, default=PasswordStrategy.email, required=False, @@ -93,9 +81,6 @@ class UserSerializer( mfa_force_enabled = serializers.BooleanField( read_only=True, label=_("MFA force enabled") ) - mfa_level_display = serializers.ReadOnlyField( - source="get_mfa_level_display", label=_("MFA level display") - ) login_blocked = serializers.BooleanField(read_only=True, label=_("Login blocked")) is_expired = serializers.BooleanField(read_only=True, label=_("Is expired")) can_public_key_auth = serializers.ReadOnlyField( @@ -108,9 +93,6 @@ class UserSerializer( allow_null=True, max_length=1024, ) - # Todo: 这里看看该怎么搞 - # can_update = serializers.SerializerMethodField(label=_('Can update')) - # can_delete = serializers.SerializerMethodField(label=_('Can delete')) custom_m2m_fields = { "system_roles": [BuiltinRole.system_user], "org_roles": [BuiltinRole.org_user], @@ -122,44 +104,22 @@ class UserSerializer( fields_mini = ["id", "name", "username"] # 只能写的字段, 这个虽然无法在框架上生效,但是更多对我们是提醒 fields_write_only = [ - "password", - "public_key", + "password", "public_key", ] # small 指的是 不需要计算的直接能从一张表中获取到的数据 - fields_small = ( - fields_mini - + fields_write_only - + [ - "email", - "wechat", - "phone", - "mfa_level", - "source", - "source_display", - "can_public_key_auth", - "need_update_password", - "mfa_enabled", - "is_service_account", - "is_valid", - "is_expired", - "is_active", # 布尔字段 - "date_expired", - "date_joined", - "last_login", # 日期字段 - "created_by", - "comment", # 通用字段 - "is_wecom_bound", - "is_dingtalk_bound", - "is_feishu_bound", - "is_otp_secret_key_bound", - "wecom_id", - "dingtalk_id", - "feishu_id", - ] - ) + fields_small = fields_mini + fields_write_only + [ + "email", "wechat", "phone", "mfa_level", "source", + "need_update_password", "mfa_enabled", + "is_service_account", "is_valid", + "is_expired", "is_active", # 布尔字段 + "is_otp_secret_key_bound", "can_public_key_auth", + "date_expired", "date_joined", + "last_login", # 日期字段 + "created_by", "comment", # 通用字段 + "wecom_id", "dingtalk_id", "feishu_id", + ] # 包含不太常用的字段,可以没有 fields_verbose = fields_small + [ - "mfa_level_display", "mfa_force_enabled", "is_first_login", "date_password_last_updated", @@ -168,25 +128,14 @@ class UserSerializer( # 外键的字段 fields_fk = [] # 多对多字段 - fields_m2m = [ - "groups", - "groups_display", - "system_roles", - "org_roles", - "system_roles_display", - "org_roles_display", - ] + fields_m2m = ["groups", "system_roles", "org_roles", ] # 在serializer 上定义的字段 fields_custom = ["login_blocked", "password_strategy"] fields = fields_verbose + fields_fk + fields_m2m + fields_custom read_only_fields = [ - "date_joined", - "last_login", - "created_by", - "is_first_login", - "wecom_id", - "dingtalk_id", + "date_joined", "last_login", "created_by", + "is_first_login", "wecom_id", "dingtalk_id", "feishu_id", ] disallow_self_update_fields = ["is_active"] @@ -205,18 +154,9 @@ class UserSerializer( "is_expired": {"label": _("Is expired")}, "avatar_url": {"label": _("Avatar url")}, "created_by": {"read_only": True, "allow_blank": True}, - "groups_display": {"label": _("Groups name")}, - "source_display": {"label": _("Source name")}, - "org_role_display": {"label": _("Organization role name")}, - "role_display": {"label": _("Super role name")}, - "total_role_display": {"label": _("Total role name")}, "role": {"default": "User"}, - "is_wecom_bound": {"label": _("Is wecom bound")}, - "is_dingtalk_bound": {"label": _("Is dingtalk bound")}, - "is_feishu_bound": {"label": _("Is feishu bound")}, "is_otp_secret_key_bound": {"label": _("Is OTP bound")}, "phone": {"validators": [PhoneValidator()]}, - "system_role_display": {"label": _("System role name")}, } def validate_password(self, password): @@ -326,8 +266,6 @@ class InviteSerializer(RolesSerializerMixin, serializers.Serializer): help_text=_("For security, only list several users"), ) system_roles = None - system_roles_display = None - org_roles_display = None class ServiceAccountSerializer(serializers.ModelSerializer):