From 3926d9ff46f26b1cfa9643d367997aefd3760786 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Tue, 14 Jan 2025 10:24:48 +0800 Subject: [PATCH] perf: Risk account --- .../automations/check_account/manager.py | 8 +++++--- apps/accounts/filters.py | 7 ++----- apps/accounts/models/account.py | 15 ++++----------- .../models/automations/check_account.py | 17 +++++++++++------ 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/apps/accounts/automations/check_account/manager.py b/apps/accounts/automations/check_account/manager.py index c212d20ff..a52a36226 100644 --- a/apps/accounts/automations/check_account/manager.py +++ b/apps/accounts/automations/check_account/manager.py @@ -194,7 +194,8 @@ class CheckAccountManager(BaseManager): now = timezone.now().isoformat() for d in self.batch_risks: - key = f'{d["account"].asset_id}_{d["account"].username}_{d["risk"]}' + account = d["account"] + key = f'{account.asset_id}_{account.username}_{d["risk"]}' origin_risk = ori_risk_map.get(key) if origin_risk and origin_risk.status != ConfirmOrIgnore.pending: @@ -209,8 +210,9 @@ class CheckAccountManager(BaseManager): update_risk(origin_risk) else: create_risk({ - "asset": d["account"].asset, - "username": d["account"].username, + "account": account, + "asset": account.asset, + "username": account.username, "risk": d["risk"], "details": [{"datetime": now, 'type': 'init'}], }) diff --git a/apps/accounts/filters.py b/apps/accounts/filters.py index 84dd82452..a4eda5ff6 100644 --- a/apps/accounts/filters.py +++ b/apps/accounts/filters.py @@ -7,7 +7,7 @@ from django_filters import rest_framework as drf_filters from assets.models import Node from common.drf.filters import BaseFilterSet from common.utils.timezone import local_zero_hour, local_now -from .models import Account, GatheredAccount, ChangeSecretRecord, AccountRisk +from .models import Account, GatheredAccount, ChangeSecretRecord class AccountFilterSet(BaseFilterSet): @@ -70,10 +70,7 @@ class AccountFilterSet(BaseFilterSet): if not value: return queryset - risks = AccountRisk.objects.filter(risk=value) - usernames = risks.values_list('username', flat=True) - assets = risks.values_list('asset', flat=True) - queryset = queryset.filter(username__in=usernames, asset__in=assets) + queryset = queryset.filter(risks__risk=value) return queryset @staticmethod diff --git a/apps/accounts/models/account.py b/apps/accounts/models/account.py index d7ee6efd4..f7185d005 100644 --- a/apps/accounts/models/account.py +++ b/apps/accounts/models/account.py @@ -1,5 +1,4 @@ from django.db import models -from django.db.models import Exists, OuterRef from django.utils.translation import gettext_lazy as _ from simple_history.models import HistoricalRecords @@ -169,20 +168,14 @@ class Account(AbsConnectivity, LabeledMixin, BaseAccount): @classmethod def get_risks(cls, queryset=None, risk_type=None): - # TODO 数据量大时,子查询性能不佳,考虑用原生sql或者在模型层面做出改动 - from accounts.models import AccountRisk - subquery = AccountRisk.objects.filter( - asset_id=OuterRef('asset_id'), - username=OuterRef('username') - ) - - if risk_type: - subquery = subquery.filter(risk=risk_type) + query = { + 'risks__risk': risk_type + } if queryset is None: queryset = cls.objects.all() - return queryset.filter(Exists(subquery)) + return queryset.filter(**query) def replace_history_model_with_mixin(): diff --git a/apps/accounts/models/automations/check_account.py b/apps/accounts/models/automations/check_account.py index 9964aa030..0bae122bd 100644 --- a/apps/accounts/models/automations/check_account.py +++ b/apps/accounts/models/automations/check_account.py @@ -58,14 +58,19 @@ class RiskChoice(TextChoices): class AccountRisk(JMSOrgBaseModel): - asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, related_name='risks', verbose_name=_('Asset')) + asset = models.ForeignKey( + 'assets.Asset', on_delete=models.CASCADE, related_name='risks', verbose_name=_('Asset') + ) + account = models.ForeignKey( + 'accounts.Account', on_delete=models.CASCADE, related_name='risks', verbose_name=_('Account'), null=True + ) + status = models.CharField( + max_length=32, choices=ConfirmOrIgnore.choices, + default=ConfirmOrIgnore.pending, blank=True, verbose_name=_('Status') + ) username = models.CharField(max_length=32, verbose_name=_('Username')) - account = models.ForeignKey('accounts.Account', on_delete=models.CASCADE, related_name='risks', - verbose_name=_('Account'), null=True) - risk = models.CharField(max_length=128, verbose_name=_('Risk'), choices=RiskChoice.choices) - status = models.CharField(max_length=32, choices=ConfirmOrIgnore.choices, default=ConfirmOrIgnore.pending, - blank=True, verbose_name=_('Status')) details = models.JSONField(default=list, verbose_name=_('Details')) + risk = models.CharField(max_length=128, verbose_name=_('Risk'), choices=RiskChoice.choices) class Meta: verbose_name = _('Account risk')