node.py 18.3 KB
Newer Older
baltery's avatar
baltery 已提交
1 2
# -*- coding: utf-8 -*-
#
baltery's avatar
baltery 已提交
3
import uuid
baltery's avatar
baltery 已提交
4
import re
baltery's avatar
baltery 已提交
5
import time
baltery's avatar
baltery 已提交
6

7
from django.db import models, transaction
8
from django.db.models import Q
9
from django.db.utils import IntegrityError
baltery's avatar
baltery 已提交
10
from django.utils.translation import ugettext_lazy as _
baltery's avatar
baltery 已提交
11
from django.utils.translation import ugettext
baltery's avatar
baltery 已提交
12
from django.core.cache import cache
baltery's avatar
baltery 已提交
13

baltery's avatar
baltery 已提交
14
from common.utils import get_logger, lazyproperty
baltery's avatar
baltery 已提交
15
from orgs.mixins.models import OrgModelMixin, OrgManager
baltery's avatar
baltery 已提交
16
from orgs.utils import get_current_org, tmp_to_org, current_org
baltery's avatar
baltery 已提交
17
from orgs.models import Organization
baltery's avatar
baltery 已提交
18

baltery's avatar
baltery 已提交
19

baltery's avatar
baltery 已提交
20
__all__ = ['Node']
baltery's avatar
baltery 已提交
21
logger = get_logger(__name__)
baltery's avatar
baltery 已提交
22 23


24 25 26 27 28
class NodeQuerySet(models.QuerySet):
    def delete(self):
        raise PermissionError("Bulk delete node deny")


baltery's avatar
baltery 已提交
29 30 31 32
class TreeCache:
    updated_time_cache_key = 'NODE_TREE_UPDATED_AT_{}'
    cache_time = 3600
    assets_updated_time_cache_key = 'NODE_TREE_ASSETS_UPDATED_AT_{}'
baltery's avatar
baltery 已提交
33

baltery's avatar
baltery 已提交
34
    def __init__(self, tree, org_id):
35
        now = time.time()
baltery's avatar
baltery 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
        self.created_time = now
        self.assets_created_time = now
        self.tree = tree
        self.org_id = org_id

    def _has_changed(self, tp="tree"):
        if tp == "assets":
            key = self.assets_updated_time_cache_key.format(self.org_id)
        else:
            key = self.updated_time_cache_key.format(self.org_id)
        updated_time = cache.get(key, 0)
        if updated_time > self.created_time:
            return True
        else:
            return False
baltery's avatar
baltery 已提交
51 52

    @classmethod
baltery's avatar
baltery 已提交
53 54 55 56 57 58 59 60
    def set_changed(cls, tp="tree", t=None, org_id=None):
        if org_id is None:
            org_id = current_org.id
        if tp == "assets":
            key = cls.assets_updated_time_cache_key.format(org_id)
        else:
            key = cls.updated_time_cache_key.format(org_id)
        ttl = cls.cache_time
baltery's avatar
baltery 已提交
61 62 63
        if not t:
            t = time.time()
        cache.set(key, t, ttl)
baltery's avatar
baltery 已提交
64

baltery's avatar
baltery 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    def tree_has_changed(self):
        return self._has_changed("tree")

    def set_tree_changed(self, t=None):
        logger.debug("Set tree tree changed")
        self.__class__.set_changed(t=t, tp="tree")

    def assets_has_changed(self):
        return self._has_changed("assets")

    def set_tree_assets_changed(self, t=None):
        logger.debug("Set tree assets changed")
        self.__class__.set_changed(t=t, tp="assets")

    def get(self):
        if self.tree_has_changed():
            self.renew()
            return self.tree
        if self.assets_has_changed():
            self.tree.init_assets()
        return self.tree

    def renew(self):
        new_obj = self.__class__.new(self.org_id)
        self.tree = new_obj.tree
        self.created_time = new_obj.created_time
        self.assets_created_time = new_obj.assets_created_time

baltery's avatar
baltery 已提交
93
    @classmethod
baltery's avatar
baltery 已提交
94 95 96 97 98 99 100 101 102 103
    def new(cls, org_id=None):
        from ..utils import TreeService
        logger.debug("Create node tree")
        if not org_id:
            org_id = current_org.id
        with tmp_to_org(org_id):
            tree = TreeService.new()
            obj = cls(tree, org_id)
            obj.tree = tree
            return obj
baltery's avatar
baltery 已提交
104

baltery's avatar
baltery 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

class TreeMixin:
    _org_tree_map = {}

    @classmethod
    def tree(cls):
        org_id = current_org.org_id()
        t = cls.get_local_tree_cache(org_id)

        if t is None:
            t = TreeCache.new()
            cls._org_tree_map[org_id] = t
        return t.get()

    @classmethod
    def get_local_tree_cache(cls, org_id=None):
        t = cls._org_tree_map.get(org_id)
        return t

    @classmethod
    def refresh_tree(cls, t=None):
        TreeCache.set_changed(tp="tree", t=t, org_id=current_org.id)

    @classmethod
    def refresh_node_assets(cls, t=None):
        TreeCache.set_changed(tp="assets", t=t, org_id=current_org.id)
baltery's avatar
baltery 已提交
131

baltery's avatar
baltery 已提交
132

baltery's avatar
baltery 已提交
133
class FamilyMixin:
baltery's avatar
baltery 已提交
134 135 136
    __parents = None
    __children = None
    __all_children = None
137
    is_node = True
baltery's avatar
baltery 已提交
138

baltery's avatar
baltery 已提交
139 140 141 142 143 144 145 146 147 148 149 150 151 152
    @staticmethod
    def clean_children_keys(nodes_keys):
        nodes_keys = sorted(list(nodes_keys), key=lambda x: (len(x), x))
        nodes_keys_clean = []
        for key in nodes_keys[::-1]:
            found = False
            for k in nodes_keys:
                if key.startswith(k + ':'):
                    found = True
                    break
            if not found:
                nodes_keys_clean.append(key)
        return nodes_keys_clean

baltery's avatar
baltery 已提交
153 154 155 156 157 158
    @classmethod
    def get_node_all_children_key_pattern(cls, key, with_self=True):
        pattern = r'^{0}:'.format(key)
        if with_self:
            pattern += r'|^{0}$'.format(key)
        return pattern
baltery's avatar
baltery 已提交
159

baltery's avatar
baltery 已提交
160 161 162
    @classmethod
    def get_node_children_key_pattern(cls, key, with_self=True):
        pattern = r'^{0}:[0-9]+$'.format(key)
baltery's avatar
baltery 已提交
163
        if with_self:
baltery's avatar
baltery 已提交
164
            pattern += r'|^{0}$'.format(key)
baltery's avatar
baltery 已提交
165 166
        return pattern

baltery's avatar
baltery 已提交
167 168 169 170 171 172 173 174 175 176
    def get_children_key_pattern(self, with_self=False):
        return self.get_node_children_key_pattern(self.key, with_self=with_self)

    def get_all_children_pattern(self, with_self=False):
        return self.get_node_all_children_key_pattern(self.key, with_self=with_self)

    def is_children(self, other):
        children_pattern = other.get_children_key_pattern(with_self=False)
        return re.match(children_pattern, self.key)

baltery's avatar
baltery 已提交
177 178
    def get_children(self, with_self=False):
        pattern = self.get_children_key_pattern(with_self=with_self)
baltery's avatar
baltery 已提交
179
        return Node.objects.filter(key__regex=pattern)
baltery's avatar
baltery 已提交
180

baltery's avatar
baltery 已提交
181 182
    def get_all_children(self, with_self=False):
        pattern = self.get_all_children_pattern(with_self=with_self)
baltery's avatar
baltery 已提交
183
        children = Node.objects.filter(key__regex=pattern)
baltery's avatar
baltery 已提交
184
        return children
baltery's avatar
baltery 已提交
185

baltery's avatar
baltery 已提交
186
    @property
baltery's avatar
baltery 已提交
187 188 189 190 191 192
    def children(self):
        return self.get_children(with_self=False)

    @property
    def all_children(self):
        return self.get_all_children(with_self=False)
baltery's avatar
baltery 已提交
193

baltery's avatar
baltery 已提交
194 195 196 197 198 199 200 201
    def create_child(self, value, _id=None):
        with transaction.atomic():
            child_key = self.get_next_child_key()
            child = self.__class__.objects.create(
                id=_id, key=child_key, value=value
            )
            return child

202 203 204 205 206 207 208 209 210 211 212 213 214 215
    def get_or_create_child(self, value, _id=None):
        """
        :return: Node, bool (created)
        """
        children = self.get_children()
        exist = children.filter(value=value).exists()
        if exist:
            child = children.filter(value=value).first()
            created = False
        else:
            child = self.create_child(value, _id)
            created = True
        return child, created

baltery's avatar
baltery 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
    def get_next_child_key(self):
        mark = self.child_mark
        self.child_mark += 1
        self.save()
        return "{}:{}".format(self.key, mark)

    def get_next_child_preset_name(self):
        name = ugettext("New node")
        values = [
            child.value[child.value.rfind(' '):]
            for child in self.get_children()
            if child.value.startswith(name)
        ]
        values = [int(value) for value in values if value.strip().isdigit()]
        count = max(values) + 1 if values else 1
        return '{} {}'.format(name, count)

    # Parents
    @classmethod
    def get_node_ancestor_keys(cls, key, with_self=False):
        parent_keys = []
        key_list = key.split(":")
        if not with_self:
            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_keys(self, with_self=False):
        return self.get_node_ancestor_keys(
            self.key, with_self=with_self
        )

    @property
    def ancestors(self):
        return self.get_ancestors(with_self=False)

    def get_ancestors(self, with_self=False):
baltery's avatar
baltery 已提交
255 256
        ancestor_keys = self.get_ancestor_keys(with_self=with_self)
        return self.__class__.objects.filter(key__in=ancestor_keys)
baltery's avatar
baltery 已提交
257

baltery's avatar
baltery 已提交
258 259 260 261 262 263 264 265
    @property
    def parent_key(self):
        parent_key = ":".join(self.key.split(":")[:-1])
        return parent_key

    def is_parent(self, other):
        return other.is_children(self)

baltery's avatar
baltery 已提交
266
    @property
baltery's avatar
baltery 已提交
267
    def parent(self):
baltery's avatar
baltery 已提交
268
        if self.is_org_root():
baltery's avatar
baltery 已提交
269
            return self
baltery's avatar
baltery 已提交
270 271
        parent_key = self.parent_key
        return Node.objects.get(key=parent_key)
baltery's avatar
baltery 已提交
272 273 274 275 276 277 278 279 280 281

    @parent.setter
    def parent(self, parent):
        if not self.is_node:
            self.key = parent.key + ':fake'
            return
        children = self.get_all_children()
        old_key = self.key
        with transaction.atomic():
            self.key = parent.get_next_child_key()
baltery's avatar
baltery 已提交
282
            self.save()
baltery's avatar
baltery 已提交
283 284 285 286
            for child in children:
                child.key = child.key.replace(old_key, self.key, 1)
                child.save()

baltery's avatar
baltery 已提交
287
    def get_siblings(self, with_self=False):
baltery's avatar
baltery 已提交
288 289 290 291 292 293 294 295 296 297
        key = ':'.join(self.key.split(':')[:-1])
        pattern = r'^{}:[0-9]+$'.format(key)
        sibling = Node.objects.filter(
            key__regex=pattern.format(self.key)
        )
        if not with_self:
            sibling = sibling.exclude(key=self.key)
        return sibling

    def get_family(self):
baltery's avatar
baltery 已提交
298
        ancestors = self.get_ancestors()
baltery's avatar
baltery 已提交
299
        children = self.get_all_children()
baltery's avatar
baltery 已提交
300
        return [*tuple(ancestors), self, *tuple(children)]
baltery's avatar
baltery 已提交
301

baltery's avatar
baltery 已提交
302 303 304 305

class FullValueMixin:
    key = ''

baltery's avatar
baltery 已提交
306
    @lazyproperty
baltery's avatar
baltery 已提交
307
    def full_value(self):
baltery's avatar
baltery 已提交
308
        if self.is_org_root():
baltery's avatar
baltery 已提交
309
            return self.value
baltery's avatar
baltery 已提交
310
        value = self.tree().get_node_full_tag(self.key)
baltery's avatar
baltery 已提交
311 312 313
        return value


baltery's avatar
baltery 已提交
314
class NodeAssetsMixin:
baltery's avatar
baltery 已提交
315
    key = ''
baltery's avatar
baltery 已提交
316
    id = None
317

baltery's avatar
baltery 已提交
318
    @lazyproperty
319
    def assets_amount(self):
baltery's avatar
baltery 已提交
320
        amount = self.tree().assets_amount(self.key)
baltery's avatar
baltery 已提交
321
        return amount
322

baltery's avatar
baltery 已提交
323 324
    def get_all_assets(self):
        from .asset import Asset
baltery's avatar
baltery 已提交
325
        if self.is_org_root():
baltery's avatar
baltery 已提交
326
            return Asset.objects.filter(org_id=self.org_id)
baltery's avatar
baltery 已提交
327 328
        pattern = '^{0}$|^{0}:'.format(self.key)
        return Asset.objects.filter(nodes__key__regex=pattern).distinct()
baltery's avatar
baltery 已提交
329 330 331

    def get_assets(self):
        from .asset import Asset
baltery's avatar
baltery 已提交
332 333
        if self.is_org_root():
            assets = Asset.objects.filter(Q(nodes=self) | Q(nodes__isnull=True))
baltery's avatar
baltery 已提交
334
        else:
baltery's avatar
baltery 已提交
335
            assets = Asset.objects.filter(nodes=self)
baltery's avatar
baltery 已提交
336
        return assets.distinct()
337

baltery's avatar
baltery 已提交
338 339
    def get_valid_assets(self):
        return self.get_assets().valid()
baltery's avatar
baltery 已提交
340

baltery's avatar
baltery 已提交
341 342 343
    def get_all_valid_assets(self):
        return self.get_all_assets().valid()

baltery's avatar
baltery 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
    @classmethod
    def _get_nodes_all_assets(cls, nodes_keys):
        """
        当节点比较多的时候,这种正则方式性能差极了
        :param nodes_keys:
        :return:
        """
        from .asset import Asset
        nodes_keys = cls.clean_children_keys(nodes_keys)
        nodes_children_pattern = set()
        for key in nodes_keys:
            children_pattern = cls.get_node_all_children_key_pattern(key)
            nodes_children_pattern.add(children_pattern)
        pattern = '|'.join(nodes_children_pattern)
        return Asset.objects.filter(nodes__key__regex=pattern).distinct()

baltery's avatar
baltery 已提交
360
    @classmethod
baltery's avatar
baltery 已提交
361
    def get_nodes_all_assets_ids(cls, nodes_keys):
baltery's avatar
baltery 已提交
362
        nodes_keys = cls.clean_children_keys(nodes_keys)
baltery's avatar
baltery 已提交
363
        assets_ids = set()
baltery's avatar
baltery 已提交
364
        for key in nodes_keys:
baltery's avatar
baltery 已提交
365 366
            node_assets_ids = cls.tree().all_assets(key)
            assets_ids.update(set(node_assets_ids))
baltery's avatar
baltery 已提交
367 368 369 370 371 372 373
        return assets_ids

    @classmethod
    def get_nodes_all_assets(cls, nodes_keys, extra_assets_ids=None):
        from .asset import Asset
        nodes_keys = cls.clean_children_keys(nodes_keys)
        assets_ids = cls.get_nodes_all_assets_ids(nodes_keys)
baltery's avatar
baltery 已提交
374 375
        if extra_assets_ids:
            assets_ids.update(set(extra_assets_ids))
baltery's avatar
baltery 已提交
376
        return Asset.objects.filter(id__in=assets_ids)
baltery's avatar
baltery 已提交
377

baltery's avatar
baltery 已提交
378

baltery's avatar
baltery 已提交
379 380 381 382 383 384 385 386
class SomeNodesMixin:
    key = ''
    default_key = '1'
    default_value = 'Default'
    ungrouped_key = '-10'
    ungrouped_value = _('ungrouped')
    empty_key = '-11'
    empty_value = _("empty")
B
BaiJiangJie 已提交
387 388
    favorite_key = '-12'
    favorite_value = _("favorite")
baltery's avatar
baltery 已提交
389 390 391 392 393 394 395 396 397 398

    def is_default_node(self):
        return self.key == self.default_key

    def is_org_root(self):
        if self.key.isdigit():
            return True
        else:
            return False

399 400 401 402 403 404 405 406 407 408 409
    @classmethod
    def get_next_org_root_node_key(cls):
        with tmp_to_org(Organization.root()):
            org_nodes_roots = cls.objects.filter(key__regex=r'^[0-9]+$')
            org_nodes_roots_keys = org_nodes_roots.values_list('key', flat=True)
            if not org_nodes_roots_keys:
                org_nodes_roots_keys = ['1']
            max_key = max([int(k) for k in org_nodes_roots_keys])
            key = str(max_key + 1) if max_key != 0 else '2'
            return key

baltery's avatar
baltery 已提交
410 411 412 413 414 415 416
    @classmethod
    def create_org_root_node(cls):
        # 如果使用current_org 在set_current_org时会死循环
        ori_org = get_current_org()
        with transaction.atomic():
            if not ori_org.is_real():
                return cls.default_node()
417
            key = cls.get_next_org_root_node_key()
baltery's avatar
baltery 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430 431
            root = cls.objects.create(key=key, value=ori_org.name)
            return root

    @classmethod
    def org_root(cls):
        root = cls.objects.filter(key__regex=r'^[0-9]+$')
        if root:
            return root[0]
        else:
            return cls.create_org_root_node()

    @classmethod
    def ungrouped_node(cls):
        with tmp_to_org(Organization.system()):
B
BaiJiangJie 已提交
432
            defaults = {'value': cls.ungrouped_value}
baltery's avatar
baltery 已提交
433 434 435 436 437 438 439 440 441
            obj, created = cls.objects.get_or_create(
                defaults=defaults, key=cls.ungrouped_key
            )
            return obj

    @classmethod
    def default_node(cls):
        with tmp_to_org(Organization.default()):
            defaults = {'value': cls.default_value}
442 443 444 445 446 447 448 449 450 451
            try:
                obj, created = cls.objects.get_or_create(
                    defaults=defaults, key=cls.default_key,
                )
            except IntegrityError as e:
                logger.error("Create default node failed: {}".format(e))
                cls.modify_other_org_root_node_key()
                obj, created = cls.objects.get_or_create(
                    defaults=defaults, key=cls.default_key,
                )
baltery's avatar
baltery 已提交
452 453
            return obj

B
BaiJiangJie 已提交
454 455 456 457 458 459 460 461 462
    @classmethod
    def favorite_node(cls):
        with tmp_to_org(Organization.system()):
            defaults = {'value': cls.favorite_value}
            obj, created = cls.objects.get_or_create(
                defaults=defaults, key=cls.favorite_key
            )
            return obj

baltery's avatar
baltery 已提交
463 464
    @classmethod
    def initial_some_nodes(cls):
465
        cls.default_node()
baltery's avatar
baltery 已提交
466
        cls.ungrouped_node()
B
BaiJiangJie 已提交
467
        cls.favorite_node()
baltery's avatar
baltery 已提交
468

469 470 471 472 473 474 475
    @classmethod
    def modify_other_org_root_node_key(cls):
        """
        解决创建 default 节点失败的问题,
        因为在其他组织下存在 default 节点,故在 DEFAULT 组织下 get 不到 create 失败
        """
        logger.info("Modify other org root node key")
476 477 478 479

        with tmp_to_org(Organization.root()):
            node_key1 = cls.objects.filter(key='1').first()
            if not node_key1:
480 481
                logger.info("Not found node that `key` = 1")
                return
482
            if not node_key1.org.is_real():
483 484
                logger.info("Org is not real for node that `key` = 1")
                return
485 486 487 488

        with transaction.atomic():
            with tmp_to_org(node_key1.org):
                org_root_node_new_key = cls.get_next_org_root_node_key()
489 490 491 492 493 494 495 496 497
                for n in cls.objects.all():
                    old_key = n.key
                    key_list = n.key.split(':')
                    key_list[0] = org_root_node_new_key
                    new_key = ':'.join(key_list)
                    n.key = new_key
                    n.save()
                    logger.info('Modify key ( {} > {} )'.format(old_key, new_key))

baltery's avatar
baltery 已提交
498 499

class Node(OrgModelMixin, SomeNodesMixin, TreeMixin, FamilyMixin, FullValueMixin, NodeAssetsMixin):
baltery's avatar
baltery 已提交
500 501 502 503 504
    id = models.UUIDField(default=uuid.uuid4, primary_key=True)
    key = models.CharField(unique=True, max_length=64, verbose_name=_("Key"))  # '1:1:1:1'
    value = models.CharField(max_length=128, verbose_name=_("Value"))
    child_mark = models.IntegerField(default=0)
    date_create = models.DateTimeField(auto_now_add=True)
baltery's avatar
baltery 已提交
505

506
    objects = OrgManager.from_queryset(NodeQuerySet)()
baltery's avatar
baltery 已提交
507 508 509 510 511 512 513 514
    is_node = True
    _parents = None

    class Meta:
        verbose_name = _("Node")
        ordering = ['key']

    def __str__(self):
baltery's avatar
baltery 已提交
515
        return self.value
baltery's avatar
baltery 已提交
516

B
BaiJiangJie 已提交
517 518 519 520 521
    # def __eq__(self, other):
    #     if not other:
    #         return False
    #     return self.id == other.id
    #
baltery's avatar
baltery 已提交
522 523 524 525 526 527
    def __gt__(self, other):
        self_key = [int(k) for k in self.key.split(':')]
        other_key = [int(k) for k in other.key.split(':')]
        self_parent_key = self_key[:-1]
        other_parent_key = other_key[:-1]

baltery's avatar
baltery 已提交
528
        if self_parent_key and self_parent_key == other_parent_key:
baltery's avatar
baltery 已提交
529 530 531 532 533 534 535 536 537
            return self.value > other.value
        return self_key > other_key

    def __lt__(self, other):
        return not self.__gt__(other)

    @property
    def name(self):
        return self.value
baltery's avatar
baltery 已提交
538

baltery's avatar
baltery 已提交
539 540
    @property
    def level(self):
baltery's avatar
baltery 已提交
541
        return len(self.key.split(':'))
baltery's avatar
baltery 已提交
542

baltery's avatar
baltery 已提交
543 544 545
    @classmethod
    def refresh_nodes(cls):
        cls.refresh_tree()
546

baltery's avatar
baltery 已提交
547
    @classmethod
baltery's avatar
baltery 已提交
548 549
    def refresh_assets(cls):
        cls.refresh_node_assets()
550

baltery's avatar
baltery 已提交
551 552 553 554 555 556 557 558 559
    def as_tree_node(self):
        from common.tree import TreeNode
        name = '{} ({})'.format(self.value, self.assets_amount)
        data = {
            'id': self.key,
            'name': name,
            'title': name,
            'pId': self.parent_key,
            'isParent': True,
baltery's avatar
baltery 已提交
560
            'open': self.is_org_root(),
baltery's avatar
baltery 已提交
561
            'meta': {
baltery's avatar
baltery 已提交
562 563 564 565 566
                'node': {
                    "id": self.id,
                    "name": self.name,
                    "value": self.value,
                    "key": self.key,
567
                    "assets_amount": self.assets_amount,
baltery's avatar
baltery 已提交
568
                },
baltery's avatar
baltery 已提交
569 570 571 572 573 574
                'type': 'node'
            }
        }
        tree_node = TreeNode(**data)
        return tree_node

baltery's avatar
baltery 已提交
575 576
    def has_children_or_has_assets(self):
        if self.children or self.get_assets().exists():
577 578 579 580
            return True
        return False

    def delete(self, using=None, keep_parents=False):
baltery's avatar
baltery 已提交
581
        if self.has_children_or_has_assets():
582 583 584
            return
        return super().delete(using=using, keep_parents=keep_parents)

baltery's avatar
baltery 已提交
585 586 587
    @classmethod
    def generate_fake(cls, count=100):
        import random
baltery's avatar
baltery 已提交
588 589 590
        org = get_current_org()
        if not org or not org.is_real():
            Organization.default().change_to()
591 592 593 594 595 596 597 598 599 600
        nodes = list(cls.objects.all())
        if count > 100:
            length = 100
        else:
            length = count

        for i in range(length):
            node = random.choice(nodes)
            child = node.create_child('Node {}'.format(i))
            print("{}. {}".format(i, child))