コード例 #1
0
ファイル: tree_extras.py プロジェクト: eikemq/specify7
def synonymize(node, into, agent):
    logger.info('synonymizing %s to %s', node, into)
    model = type(node)
    assert type(into) is model
    target = model.objects.select_for_update().get(id=into.id)
    assert node.definition_id == target.definition_id, "synonymizing across trees"
    if target.accepted_id is not None:
        raise BusinessRuleException('Synonymizing "{node.fullname}" to synonymized node "{into.fullname}".'
                                    .format(node=node, into=into))
    node.accepted_id = target.id
    node.isaccepted = False
    node.save()
    if node.children.count() > 0:
        raise BusinessRuleException('Synonymizing node "{node.fullname}" which has children.'
                                    .format(node=node))
    node.acceptedchildren.update(**{node.accepted_id_attr().replace('_id', ''): target})
    #assuming synonym can't be synonymized
    mutation_log(TREE_SYNONYMIZE, node, agent, node.parent,
                 [{'field_name': 'acceptedid','old_value': None, 'new_value': target.id},
                  {'field_name': 'isaccepted','old_value': True, 'new_value': False}])
    
    if model._meta.db_table == 'taxon':
        node.determinations.update(preferredtaxon=target)
        from .models import Determination
        Determination.objects.filter(preferredtaxon=node).update(preferredtaxon=target)
コード例 #2
0
ファイル: tree_extras.py プロジェクト: mcruz-umich/specify7
    def save(self, *args, **kwargs):
        model = type(self)
        self.rankid = self.definitionitem.rankid
        self.definition = self.definitionitem.treedef

        prev_self = None if self.id is None \
                    else model.objects.select_for_update().get(id=self.id)

        if prev_self is None:
            self.nodenumber = None
            self.highestchildnodenumber = None
        else:
            self.nodenumber = prev_self.nodenumber
            self.highestchildnodenumber = prev_self.highestchildnodenumber

        def save():
            super(Tree, self).save(*args, **kwargs)

        if prev_self is None:
            if self.parent_id is None:
                # We're creating the root of a tree.
                # Not sure if anything else needs to be
                # done here, but the validation stuff won't
                # work so skipping it.
                save()
                return

            with validate_node_numbers(self._meta.db_table):
                adding_node(self)
                save()
        elif prev_self.parent_id != self.parent_id:
            with validate_node_numbers(self._meta.db_table):
                moving_node(self)
                save()
        else:
            save()

        try:
            model.objects.get(id=self.id, parent__rankid__lt=F('rankid'))
        except model.DoesNotExist:
            raise BusinessRuleException(
                "Tree node's parent has rank greater than itself.")

        if model.objects.filter(parent=self,
                                parent__rankid__gte=F('rankid')).count() > 0:
            raise BusinessRuleException(
                "Tree node's rank is greater than some of its children.")

        if (prev_self is None or prev_self.name != self.name
                or prev_self.definitionitem_id != self.definitionitem_id
                or prev_self.parent_id != self.parent_id):
            set_fullnames(self._meta.db_table,
                          self.definition.treedefitems.count(),
                          self.definition.fullnamedirection == -1)
コード例 #3
0
def merge(node, into):
    from . import models
    logger.info('merging %s into %s', node, into)
    model = type(node)
    assert type(into) is model
    target = model.objects.select_for_update().get(id=into.id)
    assert node.definition_id == target.definition_id, "merging across trees"
    if into.accepted_id is not None:
        raise BusinessRuleException('Merging node "{node.fullname}" with synonymized node "{into.fullname}".'
                                    .format(node=node, into=into))
    target_children = target.children.select_for_update()
    for child in node.children.select_for_update():
        matched = [target_child for target_child in target_children
                   if child.name == target_child.name and child.rankid == target_child.rankid]
        if len(matched) > 0:
            merge(child, matched[0])
        else:
            child.parent = target
            child.save()

    for retry in range(100):
        try:
            node.delete()
            return
        except ProtectedError as e:
            related_model_name, field_name = re.search(r"'(\w+)\.(\w+)'$", e.args[0]).groups()
            related_model = getattr(models, related_model_name)
            assert related_model != model or field_name != 'parent', 'children were added during merge'
            related_model.objects.filter(**{field_name: node}).update(**{field_name: target})

    assert False, "failed to move all referrences to merged tree node"
コード例 #4
0
def adding_node(node):
    logger.info('adding node %s', node)
    model = type(node)
    parent = model.objects.select_for_update().get(id=node.parent.id)
    if parent.accepted_id is not None:
        raise BusinessRuleException('Adding node "{node.fullname}" to synonymized parent "{parent.fullname}".'
                                    .format(node=node, parent=parent))
    insertion_point = open_interval(model, parent.nodenumber, 1)
    node.highestchildnodenumber = node.nodenumber = insertion_point
コード例 #5
0
def synonymize(node, into):
    logger.info('synonymizing %s to %s', node, into)
    model = type(node)
    assert type(into) is model
    target = model.objects.select_for_update().get(id=into.id)
    assert node.definition_id == target.definition_id, "synonymizing across trees"
    if target.accepted_id is not None:
        raise BusinessRuleException('Synonymizing "{node.fullname}" to synonymized node "{into.fullname}".'
                                    .format(node=node, into=into))
    node.accepted_id = target.id
    node.isaccepted = False
    node.save()
    if node.children.count() > 0:
        raise BusinessRuleException('Synonymizing node "{node.fullname}" which has children.'
                                    .format(node=node))
    node.acceptedchildren.update(**{node.accepted_id_attr().replace('_id', ''): target})

    if model._meta.db_table == 'taxon':
        node.determinations.update(preferredtaxon=target)
        from .models import Determination
        Determination.objects.filter(preferredtaxon=node).update(preferredtaxon=target)
コード例 #6
0
def moving_node(to_save):
    logger.info('moving node %s', to_save)
    model = type(to_save)
    current = model.objects.get(id=to_save.id)
    size = current.highestchildnodenumber - current.nodenumber + 1
    new_parent = model.objects.select_for_update().get(id=to_save.parent.id)
    if new_parent.accepted_id is not None:
        raise BusinessRuleException('Moving node "{node.fullname}" to synonymized parent "parent.fullname".'
                                    .format(node=to_save, parent=new_parent))

    insertion_point = open_interval(model, new_parent.nodenumber, size)
    # node interval will have moved if it is to the right of the insertion point
    # so fetch again
    current = model.objects.get(id=current.id)
    move_interval(model, current.nodenumber, current.highestchildnodenumber, insertion_point)
    close_interval(model, current.nodenumber, size)

    # update the nodenumbers in to_save so the new values are not overwritten.
    current = model.objects.get(id=current.id)
    to_save.nodenumber = current.nodenumber
    to_save.highestchildnodenumber = current.highestchildnodenumber