Skip to content

Commit

Permalink
refactor: cr调整,通过slz context优化查询次数
Browse files Browse the repository at this point in the history
cr调整,通过slz context优化查询次数
  • Loading branch information
neronkl committed Mar 31, 2023
1 parent b0feeac commit 664f6ce
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 136 deletions.
4 changes: 2 additions & 2 deletions src/api/bkuser_core/api/web/global_settings/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
specific language governing permissions and limitations under the License.
"""

from rest_framework import generics, status
from rest_framework import generics
from rest_framework.response import Response

from bkuser_core.api.web.global_settings.serialziers import GlobalSettingOutputSLZ, GlobalSettingUpdateInputSLZ
Expand All @@ -36,4 +36,4 @@ def put(self, request, *args, **kwargs):
item.value = ns_settings[key]
item.save()

return Response(status=status.HTTP_204_NO_CONTENT)
return Response()
20 changes: 0 additions & 20 deletions src/api/bkuser_core/api/web/recycle_bin/constants.py

This file was deleted.

68 changes: 43 additions & 25 deletions src/api/bkuser_core/api/web/recycle_bin/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,69 +11,87 @@

from rest_framework import serializers

from bkuser_core.api.web.utils import get_category_display_name_map
from bkuser_core.departments.models import Department
from bkuser_core.profiles.models import Profile
from bkuser_core.recycle_bin.models import RecycleBin


class RecycleBinSearchInputSlZ(serializers.Serializer):
keyword = serializers.CharField(required=False, help_text="搜索关键词")


class RecycleBinBaseSerializer(serializers.ModelSerializer):
expires = serializers.IntegerField(help_text="过期剩余天数")

class Meta:
model = RecycleBin
exclude = ["create_time", "update_time", "object_type", "object_id", "status"]


class RecycleBinCategoryOutputSlZ(RecycleBinBaseSerializer):
class RecycleBinCategoryOutputSlZ(serializers.ModelSerializer):
category = serializers.SerializerMethodField(help_text="目录基础信息")
profile_count = serializers.IntegerField(help_text="目录下人员数量")
department_count = serializers.IntegerField(help_text="目录下部门数量")
profile_count = serializers.SerializerMethodField(help_text="目录下人员数量")
department_count = serializers.SerializerMethodField(help_text="目录下部门数量")
expires = serializers.IntegerField(help_text="过期剩余天数")

def get_category(self, instance):
category = instance.get_relate_object()
category = self.context["category_map"][instance.object_id]
return {
"id": category.id,
"display_name": category.display_name,
"domain": category.domain,
"type": category.type,
}

def get_profile_count(self, instance):
return Profile.objects.filter(category_id=instance.object_id).count()

def get_department_count(self, instance):
return Department.objects.filter(category_id=instance.object_id).count()

class Meta:
model = RecycleBin
fields = ["id", "expires", "category", "profile_count", "department_count", "operator"]

class RecycleBinDepartmentOutputSlZ(RecycleBinBaseSerializer):

class RecycleBinDepartmentOutputSlZ(serializers.ModelSerializer):
category_display_name = serializers.SerializerMethodField(help_text="所属目录名称")
department = serializers.SerializerMethodField(help_text="部门基础信息")
profile_count = serializers.IntegerField(help_text="部门下人员数量")
profile_count = serializers.SerializerMethodField(help_text="部门下人员数量")
expires = serializers.IntegerField(help_text="过期剩余天数")

def get_department(self, instance):
department = instance.get_relate_object()
department = self.context["department_map"][instance.object_id]
return {
"id": department.id,
"name": department.name,
"ancestor": department.parent.name if department.parent else "",
"children": department.children.all().count(),
"parent_name": department.parent.name if department.parent else "",
"children_count": department.children.all().count(),
}

def get_category_display_name(self, instance):
department = instance.get_relate_object()
return get_category_display_name_map()[department.category_id]
department = self.context["department_map"][instance.object_id]
return self.context["category_display_name_map"][department.category_id]

def get_profile_count(self, instance):
return self.context["department_map"][instance.object_id].profiles.count()

class Meta:
model = RecycleBin
fields = ["id", "expires", "category_display_name", "department", "profile_count", "operator"]


class RecycleBinProfileOutputSlZ(RecycleBinBaseSerializer):
class RecycleBinProfileOutputSlZ(serializers.ModelSerializer):
category_display_name = serializers.SerializerMethodField(help_text="所属目录信息")
profile = serializers.SerializerMethodField(help_text="人员基础信息")
expires = serializers.IntegerField(help_text="过期剩余天数")

def get_profile(self, instance):
profile = instance.get_relate_object()
profile = self.context["profile_map"][instance.object_id]
return {
"id": profile.id,
"username": f"{profile.username}@{profile.domain}",
"username": profile.username,
"domain": profile.domain,
"display_name": profile.display_name,
"department": profile.departments.values("id", "name"),
}

def get_category_display_name(self, instance):
profile = instance.get_relate_object()
return get_category_display_name_map()[profile.category_id]
profile = self.context["profile_map"][instance.object_id]
return self.context["category_display_name_map"][profile.category_id]

class Meta:
model = RecycleBin
fields = ["id", "expires", "category_display_name", "profile", "operator"]
6 changes: 3 additions & 3 deletions src/api/bkuser_core/api/web/recycle_bin/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@

urlpatterns = [
path(
"category/",
"categories/",
views.RecycleBinCategoryListApi.as_view(),
name="recycle_bin.category.list",
),
path(
"department/",
"departments/",
views.RecycleBinDepartmentListApi.as_view(),
name="recycle_bin.department.list",
),
path(
"profile/",
"profiles/",
views.RecycleBinProfileListApi.as_view(),
name="recycle_bin.profile.list",
),
Expand Down
166 changes: 128 additions & 38 deletions src/api/bkuser_core/api/web/recycle_bin/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,78 +8,168 @@
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
import functools
from operator import or_

from django.db.models import Q
from rest_framework import generics

from bkuser_core.api.web.recycle_bin.constants import RECYCLE_BIN_OBJECT_MAP
from bkuser_core.api.web.recycle_bin.serializers import (
RecycleBinCategoryOutputSlZ,
RecycleBinDepartmentOutputSlZ,
RecycleBinProfileOutputSlZ,
RecycleBinSearchInputSlZ,
)
from bkuser_core.api.web.utils import get_category_display_name_map
from bkuser_core.api.web.viewset import CustomPagination
from bkuser_core.recycle_bin.constants import RecycleBinObjectStatus, RecycleBinObjectType
from bkuser_core.categories.constants import CategoryStatus
from bkuser_core.categories.models import ProfileCategory
from bkuser_core.departments.models import Department
from bkuser_core.profiles.constants import ProfileStatus
from bkuser_core.profiles.models import Profile
from bkuser_core.recycle_bin.constants import RecycleBinObjectType
from bkuser_core.recycle_bin.models import RecycleBin


class RecycleBinBaseListApi(generics.ListAPIView):
class RecycleBinCategoryListApi(generics.ListAPIView):
"""
回收站展示基础类
回收站:目录展示
"""

object_type: str = ""
search_fields: list = []
queryset = RecycleBin.objects.filter(status=RecycleBinObjectStatus.SOFT_DELETED.value)
serializer_class = RecycleBinCategoryOutputSlZ
queryset = RecycleBin.objects.filter(object_type=RecycleBinObjectType.CATEGORY.value)
pagination_class = CustomPagination

def get_queryset(self):
queryset = self.queryset.filter(object_type=self.object_type)
input_slz = RecycleBinSearchInputSlZ(data=self.request.query_params)
input_slz.is_valid(raise_exception=True)
data = input_slz.validated_data

keyword = data.get("keyword")
queryset = self.queryset
# TODO 此处通过大表模糊查询,获取小表对象,待更好的方案进行优化
if keyword:
# Q 连接对应search_filed 和 keyword
condition_combos = [Q(**{"{}__icontains".format(filed): keyword}) for filed in self.search_fields]
query = functools.reduce(or_, condition_combos)
object_ids = RECYCLE_BIN_OBJECT_MAP[self.object_type].objects.filter(query).values_list("id", flat=True)
queryset = queryset.filter(object_id__in=object_ids)
return queryset

def list(self, request, *args, **kwargs):
return super(RecycleBinBaseListApi, self).list(request, *args, **kwargs)


class RecycleBinCategoryListApi(RecycleBinBaseListApi):
"""
回收站:目录展示
"""

object_type = RecycleBinObjectType.CATEGORY.value
serializer_class = RecycleBinCategoryOutputSlZ
search_fields = ["domain", "display_name"]


class RecycleBinDepartmentListApi(RecycleBinBaseListApi):
category_ids = ProfileCategory.objects.filter(
Q(domain__icontains=keyword) | Q(display_name__icontains=keyword),
enabled=False,
status=CategoryStatus.INACTIVE.value,
).values_list("id", flat=True)
queryset = queryset.filter(object_id__in=category_ids)
return queryset.all()

def get_serializer_context(self):
output_slz_context = super(RecycleBinCategoryListApi, self).get_serializer_context()

categories = ProfileCategory.objects.all()
category_map: dict = {}
for category in categories:
category_map[category.id] = category

output_slz_context.update(
{
"category_map": category_map,
}
)
return output_slz_context


class RecycleBinDepartmentListApi(generics.ListAPIView):
"""
回收站:组织展示
"""

object_type = RecycleBinObjectType.DEPARTMENT.value
serializer_class = RecycleBinDepartmentOutputSlZ
search_fields = ["name"]
queryset = RecycleBin.objects.filter(object_type=RecycleBinObjectType.DEPARTMENT.value)
pagination_class = CustomPagination

def get_queryset(self):
input_slz = RecycleBinSearchInputSlZ(data=self.request.query_params)
input_slz.is_valid(raise_exception=True)
data = input_slz.validated_data

class RecycleBinProfileListApi(RecycleBinBaseListApi):
keyword = data.get("keyword")
queryset = self.queryset
# TODO 此处通过大表模糊查询,获取小表对象,待更好的方案进行优化
if keyword:
department_ids = Department.objects.filter(name__icontains=keyword, enabled=False).values_list(
"id", flat=True
)
queryset = queryset.filter(object_id__in=department_ids)
return queryset.all()

def get_serializer_context(self, object_ids: list):
output_slz_context = super(RecycleBinDepartmentListApi, self).get_serializer_context()

departments = Department.objects.filter(id__in=object_ids)
department_map: dict = {}
for department in departments:
department_map[department.id] = department

category_display_name_map = get_category_display_name_map()

output_slz_context.update(
{
"category_display_name_map": category_display_name_map,
"department_map": department_map,
}
)
return output_slz_context

def get_serializer(self, *args, **kwargs):
queryset = args[0]
object_ids: list = []
for item in queryset:
object_ids.append(item.object_id)
serializer_class = self.get_serializer_class()
kwargs.setdefault('context', self.get_serializer_context(object_ids))
return serializer_class(*args, **kwargs)


class RecycleBinProfileListApi(generics.ListAPIView):
"""
回收站:人员展示
"""

object_type = RecycleBinObjectType.PROFILE.value
serializer_class = RecycleBinProfileOutputSlZ
search_fields = ["username", "display_name"]
queryset = RecycleBin.objects.filter(object_type=RecycleBinObjectType.PROFILE.value)
pagination_class = CustomPagination

def get_queryset(self):
input_slz = RecycleBinSearchInputSlZ(data=self.request.query_params)
input_slz.is_valid(raise_exception=True)
data = input_slz.validated_data

keyword = data.get("keyword")
queryset = self.queryset
# TODO 此处通过大表模糊查询,获取小表对象,待更好的方案进行优化
if keyword:
profile_ids = Profile.objects.filter(
Q(username__icontains=keyword) | Q(display_name__icontains=keyword),
enabled=False,
status=ProfileStatus.DELETED.value,
).values_list("id", flat=True)
queryset = queryset.filter(object_id__in=profile_ids)
return queryset.all()

def get_serializer_context(self, object_ids: list):
output_slz_context = super(RecycleBinProfileListApi, self).get_serializer_context()

profiles = Profile.objects.filter(id__in=object_ids)
profile_map: dict = {}
for profile in profiles:
profile_map[profile.id] = profile
category_display_name_map = get_category_display_name_map()

output_slz_context.update(
{
"category_display_name_map": category_display_name_map,
"profile_map": profile_map,
}
)
return output_slz_context

def get_serializer(self, *args, **kwargs):
queryset = args[0]
object_ids: list = []
for item in queryset:
object_ids.append(item.object_id)
serializer_class = self.get_serializer_class()
kwargs.setdefault('context', self.get_serializer_context(object_ids))
return serializer_class(*args, **kwargs)
8 changes: 0 additions & 8 deletions src/api/bkuser_core/recycle_bin/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,3 @@ class RecycleBinObjectType(AutoNameEnum):
PROFILE = auto()

_choices_labels = ((CATEGORY, "用户目录"), (DEPARTMENT, "部门组织"), (PROFILE, "人员"))


class RecycleBinObjectStatus(AutoNameEnum):
SOFT_DELETED = auto()
HARD_DELETED = auto()
REVERTING = auto()

_choices_labels = ((SOFT_DELETED, "软删除"), (HARD_DELETED, "硬删除"), (REVERTING, "还原"))
1 change: 0 additions & 1 deletion src/api/bkuser_core/recycle_bin/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class Migration(migrations.Migration):
('object_type', models.CharField(choices=[('CATEGORY', '用户目录'), ('DEPARTMENT', '部门组织'), ('PROFILE', '人员')], default='', max_length=64, verbose_name='对象类型')),
('object_id', models.IntegerField(verbose_name='对象id')),
('operator', models.CharField(default='', max_length=255, verbose_name='操作人')),
('status', models.CharField(choices=[('SOFT_DELETED', '软删除'), ('HARD_DELETED', '硬删除'), ('REVERTING', '还原')], default='SOFT_DELETED', max_length=64, verbose_name='数据状态')),
],
options={
'verbose_name': '回收站信息',
Expand Down
Loading

0 comments on commit 664f6ce

Please sign in to comment.