Unverified Commit b95f8a7d authored by 老广's avatar 老广 Committed by GitHub

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

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