From 90090a7fc77f8243689d23ed40b59b6a748827e9 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 27 Apr 2023 14:13:40 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=B7=BB=E5=8A=A0=20JSONManyToManyFiel?= =?UTF-8?q?dSerializer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/serializers/base.py | 26 ++++---------------------- apps/common/db/fields.py | 24 ++++++++++++------------ apps/common/serializers/fields.py | 17 ++++++++++++++++- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/apps/acls/serializers/base.py b/apps/acls/serializers/base.py index dbdac67e7..ca319284f 100644 --- a/apps/acls/serializers/base.py +++ b/apps/acls/serializers/base.py @@ -2,7 +2,7 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from acls.models.base import ActionChoices -from common.serializers.fields import LabeledChoiceField, ObjectRelatedField +from common.serializers.fields import JSONManyToManyField, ObjectRelatedField, LabeledChoiceField from orgs.models import Organization from users.models import User @@ -52,25 +52,9 @@ class ACLAccountsSerializer(serializers.Serializer): class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer): - users = ACLUsersSerializer(label=_('User')) - assets = ACLAssestsSerializer(label=_('Asset')) - accounts = ACLAccountsSerializer(label=_('Account')) - users_username_group = serializers.ListField( - source='users.username_group', read_only=True, child=serializers.CharField(), - label=_('User (username)') - ) - assets_name_group = serializers.ListField( - source='assets.name_group', read_only=True, child=serializers.CharField(), - label=_('Asset (name)') - ) - assets_address_group = serializers.ListField( - source='assets.address_group', read_only=True, child=serializers.CharField(), - label=_('Asset (address)') - ) - accounts_username_group = serializers.ListField( - source='accounts.username_group', read_only=True, child=serializers.CharField(), - label=_('Account (username)') - ) + users = JSONManyToManyField(label=_('User')) + assets = JSONManyToManyField(label=_('Asset')) + accounts = JSONManyToManyField(label=_('Account')) reviewers = ObjectRelatedField( queryset=User.objects, many=True, required=False, label=_('Reviewers') ) @@ -84,8 +68,6 @@ class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer): class Meta: fields_mini = ["id", "name"] fields_small = fields_mini + [ - 'users_username_group', 'assets_address_group', 'assets_name_group', - 'accounts_username_group', "users", "accounts", "assets", "is_active", "date_created", "date_updated", "priority", "action", "comment", "created_by", "org_id", diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index c80c2b84d..50f7bb60a 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -429,29 +429,29 @@ class JSONManyToManyField(models.JSONField): return name, path, args, kwargs @staticmethod - def _check_value(val): + def check_value(val): if not val: return val - e = ValueError( - 'Invalid JSON data for JSONManyToManyField, should be like ' - '{"type": "all"} or {"type": "ids", "ids": []} ' - 'or {"type": "attrs", "attrs": [{"name": "ip", "match": "exact", "value": "value"}' - ) + e = ValueError(_( + "Invalid JSON data for JSONManyToManyField, should be like " + "{'type': 'all'} or {'type': 'ids', 'ids': []} " + "or {'type': 'attrs', 'attrs': [{'name': 'ip', 'match': 'exact', 'value': 'value'}" + )) if not isinstance(val, dict): raise e if val["type"] not in ["all", "ids", "attrs"]: - raise e + raise ValueError(_('Invalid type, should be "all", "ids" or "attrs"')) if val["type"] == "ids": if not isinstance(val["ids"], list): - raise e + raise ValueError(_("Invalid ids for ids, should be a list")) elif val["type"] == "attrs": if not isinstance(val["attrs"], list): - raise e + raise ValueError(_("Invalid attrs, should be a list of dict")) for attr in val["attrs"]: if not isinstance(attr, dict): - raise e + raise ValueError(_("Invalid attrs, should be a list of dict")) if 'name' not in attr or 'value' not in attr: - raise e + raise ValueError(_("Invalid attrs, should be has name and value")) def get_db_prep_value(self, value, connection, prepared=False): return self.get_prep_value(value) @@ -461,7 +461,7 @@ class JSONManyToManyField(models.JSONField): return None if isinstance(value, RelatedManager): value = value.value - self._check_value(value) + self.check_value(value) return json.dumps(value) def validate(self, value, model_instance): diff --git a/apps/common/serializers/fields.py b/apps/common/serializers/fields.py index 0b1e7040c..9595e09e1 100644 --- a/apps/common/serializers/fields.py +++ b/apps/common/serializers/fields.py @@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from rest_framework.fields import ChoiceField, empty -from common.db.fields import TreeChoices +from common.db.fields import TreeChoices, JSONManyToManyField as ModelJSONManyToManyField from common.local import add_encrypted_field_set from common.utils import decrypt_password @@ -20,6 +20,7 @@ __all__ = [ "TreeChoicesField", "LabeledMultipleChoiceField", "PhoneField", + "JSONManyToManyField" ] @@ -216,3 +217,17 @@ class PhoneField(serializers.CharField): phone = phonenumbers.parse(value, 'CN') value = {'code': '+%s' % phone.country_code, 'phone': phone.national_number} return value + + +class JSONManyToManyField(serializers.JSONField): + def to_representation(self, value): + return value.value + + def to_internal_value(self, data): + if not data: + data = {} + try: + ModelJSONManyToManyField.check_value(data) + except ValueError as e: + raise serializers.ValidationError(e) + return super().to_internal_value(data)