未验证 提交 b95f8a7d 编写于 作者: baltery's avatar baltery 提交者: GitHub

[Update] 修复获取节点数量比较慢的问题 (#2184)

上级 985bd6fc
......@@ -20,11 +20,10 @@ from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404
from django.db.models import Count
from common.utils import get_logger, get_object_or_none
from ..hands import IsOrgAdmin
from ..models import Node
from ..models import Node, Asset
from ..tasks import update_assets_hardware_info_util, test_asset_connectability_util
from .. import serializers
......
......@@ -22,7 +22,9 @@ class Node(OrgModelMixin):
date_create = models.DateTimeField(auto_now_add=True)
is_node = True
_full_value_cache_key_prefix = '_NODE_VALUE_{}'
_assets_amount = None
_full_value_cache_key = '_NODE_VALUE_{}'
_assets_amount_cache_key = '_NODE_ASSETS_AMOUNT_{}'
class Meta:
verbose_name = _("Node")
......@@ -49,30 +51,56 @@ class Node(OrgModelMixin):
def name(self):
return self.value
@property
def assets_amount(self):
"""
获取节点下所有资产数量速度太慢,所以需要重写,使用cache等方案
:return:
"""
if self._assets_amount is not None:
return self._assets_amount
cache_key = self._assets_amount_cache_key.format(self.key)
cached = cache.get(cache_key)
if cached is not None:
return cached
assets_amount = self.get_all_assets().count()
cache.set(cache_key, assets_amount, 3600)
return assets_amount
@assets_amount.setter
def assets_amount(self, value):
self._assets_amount = value
def expire_assets_amount(self):
ancestor_keys = self.get_ancestor_keys(with_self=True)
cache_keys = [self._assets_amount_cache_key.format(k) for k in ancestor_keys]
cache.delete_many(cache_keys)
@classmethod
def expire_nodes_assets_amount(cls, nodes=None):
if nodes:
for node in nodes:
node.expire_assets_amount()
return
key = cls._assets_amount_cache_key.format('*')
cache.delete_pattern(key)
@property
def full_value(self):
key = self._full_value_cache_key_prefix.format(self.key)
key = self._full_value_cache_key.format(self.key)
cached = cache.get(key)
if cached:
return cached
value = self.get_full_value()
self.cache_full_value(value)
return value
def get_full_value(self):
# ancestor = [a.value for a in self.get_ancestor(with_self=True)]
if self.is_root():
return self.value
parent_full_value = self.parent.full_value
value = parent_full_value + ' / ' + self.value
return value
def cache_full_value(self, value):
key = self._full_value_cache_key_prefix.format(self.key)
key = self._full_value_cache_key.format(self.key)
cache.set(key, value, 3600)
return value
def expire_full_value(self):
key = self._full_value_cache_key_prefix.format(self.key)
key = self._full_value_cache_key.format(self.key)
cache.delete_pattern(key+'*')
@property
......@@ -182,17 +210,18 @@ class Node(OrgModelMixin):
child.save()
self.save()
def get_ancestor(self, with_self=False):
if self.is_root():
root = self.__class__.root()
return [root]
_key = self.key.split(':')
def get_ancestor_keys(self, with_self=False):
parent_keys = []
key_list = self.key.split(":")
if not with_self:
_key.pop()
ancestor_keys = []
for i in range(len(_key)):
ancestor_keys.append(':'.join(_key))
_key.pop()
key_list.pop()
for i in range(len(key_list)):
parent_keys.append(":".join(key_list))
key_list.pop()
return parent_keys
def get_ancestor(self, with_self=False):
ancestor_keys = self.get_ancestor_keys(with_self=with_self)
ancestor = self.__class__.objects.filter(
key__in=ancestor_keys
).order_by('key')
......@@ -227,10 +256,6 @@ class Node(OrgModelMixin):
defaults = {'value': 'Default'}
return cls.objects.get_or_create(defaults=defaults, key='1')
@classmethod
def get_tree_name_ref(cls):
pass
@classmethod
def generate_fake(cls, count=100):
import random
......
......@@ -43,7 +43,7 @@ class NodeGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class NodeSerializer(serializers.ModelSerializer):
assets_amount = serializers.SerializerMethodField()
assets_amount = serializers.IntegerField()
tree_id = serializers.SerializerMethodField()
tree_parent = serializers.SerializerMethodField()
......@@ -53,6 +53,10 @@ class NodeSerializer(serializers.ModelSerializer):
'id', 'key', 'value', 'assets_amount',
'is_node', 'org_id', 'tree_id', 'tree_parent',
]
read_only_fields = [
'id', 'key', 'assets_amount', 'is_node',
'org_id',
]
list_serializer_class = BulkListSerializer
def validate(self, data):
......@@ -66,12 +70,6 @@ class NodeSerializer(serializers.ModelSerializer):
)
return data
@staticmethod
def get_assets_amount(obj):
if hasattr(obj, 'assets_amount'):
return obj.assets_amount
return obj.get_all_assets().count()
@staticmethod
def get_tree_id(obj):
return obj.key
......@@ -80,12 +78,6 @@ class NodeSerializer(serializers.ModelSerializer):
def get_tree_parent(obj):
return obj.parent_key
def get_fields(self):
fields = super().get_fields()
field = fields["key"]
field.required = False
return fields
class NodeAssetsSerializer(serializers.ModelSerializer):
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
......
# -*- coding: utf-8 -*-
#
from collections import defaultdict
from django.db.models.signals import post_save, m2m_changed
from django.db.models.signals import post_save, m2m_changed, post_delete
from django.dispatch import receiver
from common.utils import get_logger
......@@ -35,6 +35,17 @@ def on_asset_created_or_update(sender, instance=None, created=False, **kwargs):
update_asset_hardware_info_on_created(instance)
test_asset_conn_on_created(instance)
# 过期节点资产数量
nodes = instance.nodes.all()
Node.expire_nodes_assets_amount(nodes)
@receiver(post_delete, sender=Asset, dispatch_uid="my_unique_identifier")
def on_asset_delete(sender, instance=None, **kwargs):
# 过期节点资产数量
nodes = instance.nodes.all()
Node.expire_nodes_assets_amount(nodes)
@receiver(post_save, sender=SystemUser, dispatch_uid="my_unique_identifier")
def on_system_user_update(sender, instance=None, created=True, **kwargs):
......@@ -63,10 +74,11 @@ def on_system_user_assets_change(sender, instance=None, **kwargs):
@receiver(m2m_changed, sender=Asset.nodes.through)
def on_asset_node_changed(sender, instance=None, **kwargs):
logger.debug("Asset node change signal received")
if isinstance(instance, Asset):
if kwargs['action'] == 'post_add':
logger.debug("Asset node change signal received")
nodes = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
Node.expire_nodes_assets_amount(nodes)
system_users_assets = defaultdict(set)
system_users = SystemUser.objects.filter(nodes__in=nodes)
# 清理节点缓存
......@@ -79,9 +91,11 @@ def on_asset_node_changed(sender, instance=None, **kwargs):
@receiver(m2m_changed, sender=Asset.nodes.through)
def on_node_assets_changed(sender, instance=None, **kwargs):
if isinstance(instance, Node):
logger.debug("Node assets change signal received")
# 当节点和资产关系发生改变时,过期资产数量缓存
instance.expire_assets_amount()
assets = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
if kwargs['action'] == 'post_add':
logger.debug("Node assets change signal received")
# 重新关联系统用户和资产的关系
system_users = SystemUser.objects.filter(nodes=instance)
for system_user in system_users:
......
......@@ -116,6 +116,7 @@ function initTree2() {
$(document).ready(function(){
}).on('show.bs.modal', function () {
initTable2();
initTree2();
})
......
......@@ -305,6 +305,9 @@ function onSelected(event, treeNode) {
}
function selectQueryNode() {
// TODO: 是否应该添加
// 暂时忽略之前选中的内容
return
var query_node_id = $.getUrlParam("node");
var cookie_node_id = getCookie('node_selected');
var node;
......@@ -355,6 +358,9 @@ function onDrop(event, treeId, treeNodes, targetNode, moveType) {
}
function initTree() {
if (zTree) {
return
}
var setting = {
view: {
dblClickExpand: false,
......@@ -387,6 +393,7 @@ function initTree() {
};
var zNodes = [];
console.log("Get assets")
$.get("{% url 'api-assets:node-list' %}", function(data, status){
$.each(data, function (index, value) {
value["node_id"] = value["id"];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册