openslides_backend/action/relations/single_relation_handler.py
def perform(self) -> RelationFieldUpdates:
        """
        Main method of this handler. It calculates which relation fields have to be updated
        according to the changes in self.field.
        """
        # Prepare the new value of our field and the real field name of the reverse field.
        value = self.instance.get(self.field_name)
        rel_ids = transform_to_fqids(value, self.field.get_target_collection())
        # We transform everything to lists of fqids to unify the handling. The values are
        # later transformed back

        # Just check if we have an invalid use case here.
        if isinstance(self.field, BaseTemplateRelationField):
            if self.field.is_template_field(self.field_name):
                raise ValueError(
                    "You can not handle template fields here. Use them with populated replacements."
                )

        # calculated the fqids which have to be added/remove and partition them by collection
        # since every collection might have a different related field
        add, remove = self.relation_diffs(rel_ids)
        changed_fqids = list(add | remove)

        add_per_collection = self.partition_by_collection(add)
        remove_per_collection = self.partition_by_collection(remove)
        changed_fqids_per_collection = self.partition_by_collection(changed_fqids)

        final = {}
        for collection in list(add_per_collection.keys()) + list(
            remove_per_collection.keys()
        ):
            if collection not in self.field.to:
                raise ActionException(
                    f"The collection '{collection.collection}' is not available for field '{self.field.own_field_name}' in collection '{self.field.own_collection.collection}'."
                )

            related_name = self.get_related_name(collection)
            related_field = self.get_reverse_field(collection)

            # acquire all related models with the related fields
            rels: Dict[FullQualifiedId, PartialModel] = defaultdict(dict)
            for fqid in changed_fqids_per_collection[collection]:
                related_model = self.datastore.fetch_model(
                    fqid,
                    [related_name],
                    get_deleted_models=DeletedModelsBehaviour.NO_DELETED,
                    exception=False,
                )
                # again, we transform everything to lists of fqids
                rels[fqid][related_name] = transform_to_fqids(
                    related_model.get(related_name), self.model.collection
                )

            # calculate actual updates
            result = self.prepare_result(
                add_per_collection[collection],
                remove_per_collection[collection],
                rels,
                related_name,
            )
            for fqfield, rel_update in result.items():
                # transform fqids back to ids
                if not isinstance(related_field, BaseGenericRelationField):
                    modified_element = rel_update["modified_element"]
                    assert isinstance(modified_element, FullQualifiedId)
                    rel_update["modified_element"] = modified_element.id

                    fqids = cast(List[FullQualifiedId], rel_update["value"])
                    rel_update["value"] = [fqid.id for fqid in fqids]

                # remove arrays in *:1 cases which we artificially added
                current_value = cast(
                    Union[List[int], List[FullQualifiedId]], rel_update["value"]
                )
                if self.type in ("1:1", "m:1"):
                    if len(current_value) == 0:
                        rel_update["value"] = None
                    else:
                        rel_update["value"] = current_value[0]

            final.update(result)

            # update the reverse template field in the case of a structured field
            if isinstance(related_field, BaseTemplateField):
                result_template_field = self.prepare_result_template_field(result)
                final.update(result_template_field)

        for chained_field in self.chained_fields:
            handler = self.build_handler_from_chained_field(chained_field)
            result = handler.perform()
            final.update(result)
        return final

        Main method of this handler. It calculates which relation fields have to be updated
        according to the changes in self.field.
        
Main method of this handler. It calculates which relation fields have to be updated
according to the changes in self.field.
Main method of this handler . It calculates which relation fields have to be updated according to the changes in self . field .
def perform(self) -> RelationFieldUpdates:
        value = self.instance.get(self.field_name)
        rel_ids = transform_to_fqids(value, self.field.get_target_collection())
        if isinstance(self.field, BaseTemplateRelationField):
            if self.field.is_template_field(self.field_name):
                raise ValueError(
                    "You can not handle template fields here. Use them with populated replacements."
                )
        add, remove = self.relation_diffs(rel_ids)
        changed_fqids = list(add | remove)
        add_per_collection = self.partition_by_collection(add)
        remove_per_collection = self.partition_by_collection(remove)
        changed_fqids_per_collection = self.partition_by_collection(changed_fqids)
        final = {}
        for collection in list(add_per_collection.keys()) + list(
            remove_per_collection.keys()
        ):
            if collection not in self.field.to:
                raise ActionException(
                    f"The collection '{collection.collection}' is not available for field '{self.field.own_field_name}' in collection '{self.field.own_collection.collection}'."
                )
            related_name = self.get_related_name(collection)
            related_field = self.get_reverse_field(collection)
            rels: Dict[FullQualifiedId, PartialModel] = defaultdict(dict)
            for fqid in changed_fqids_per_collection[collection]:
                related_model = self.datastore.fetch_model(
                    fqid,
                    [related_name],
                    get_deleted_models=DeletedModelsBehaviour.NO_DELETED,
                    exception=False,
                )
                rels[fqid][related_name] = transform_to_fqids(
                    related_model.get(related_name), self.model.collection
                )
            result = self.prepare_result(
                add_per_collection[collection],
                remove_per_collection[collection],
                rels,
                related_name,
            )
            for fqfield, rel_update in result.items():
                if not isinstance(related_field, BaseGenericRelationField):
                    modified_element = rel_update["modified_element"]
                    assert isinstance(modified_element, FullQualifiedId)
                    rel_update["modified_element"] = modified_element.id
                    fqids = cast(List[FullQualifiedId], rel_update["value"])
                    rel_update["value"] = [fqid.id for fqid in fqids]
                current_value = cast(
                    Union[List[int], List[FullQualifiedId]], rel_update["value"]
                )
                if self.type in ("1:1", "m:1"):
                    if len(current_value) == 0:
                        rel_update["value"] = None
                    else:
                        rel_update["value"] = current_value[0]
            final.update(result)
            if isinstance(related_field, BaseTemplateField):
                result_template_field = self.prepare_result_template_field(result)
                final.update(result_template_field)
        for chained_field in self.chained_fields:
            handler = self.build_handler_from_chained_field(chained_field)
            result = handler.perform()
            final.update(result)
        return final
def perform ( self ) -> RelationFieldUpdates : value = self . instance . get ( self . field_name ) rel_ids = transform_to_fqids ( value , self . field . get_target_collection ( ) ) if isinstance ( self . field , BaseTemplateRelationField ) : if self . field . is_template_field ( self . field_name ) : raise ValueError ( "You can not handle template fields here. Use them with populated replacements." ) add , remove = self . relation_diffs ( rel_ids ) changed_fqids = list ( add | remove ) add_per_collection = self . partition_by_collection ( add ) remove_per_collection = self . partition_by_collection ( remove ) changed_fqids_per_collection = self . partition_by_collection ( changed_fqids ) final = { } for collection in list ( add_per_collection . keys ( ) ) + list ( remove_per_collection . keys ( ) ) : if collection not in self . field . to : raise ActionException ( f"The collection '{collection.collection}' is not available for field '{self.field.own_field_name}' in collection '{self.field.own_collection.collection}'." ) related_name = self . get_related_name ( collection ) related_field = self . get_reverse_field ( collection ) rels : Dict [ FullQualifiedId , PartialModel ] = defaultdict ( dict ) for fqid in changed_fqids_per_collection [ collection ] : related_model = self . datastore . fetch_model ( fqid , [ related_name ] , get_deleted_models = DeletedModelsBehaviour . NO_DELETED , exception = False , ) rels [ fqid ] [ related_name ] = transform_to_fqids ( related_model . get ( related_name ) , self . model . collection ) result = self . prepare_result ( add_per_collection [ collection ] , remove_per_collection [ collection ] , rels , related_name , ) for fqfield , rel_update in result . items ( ) : if not isinstance ( related_field , BaseGenericRelationField ) : modified_element = rel_update [ "modified_element" ] assert isinstance ( modified_element , FullQualifiedId ) rel_update [ "modified_element" ] = modified_element . id fqids = cast ( List [ FullQualifiedId ] , rel_update [ "value" ] ) rel_update [ "value" ] = [ fqid . id for fqid in fqids ] current_value = cast ( Union [ List [ int ] , List [ FullQualifiedId ] ] , rel_update [ "value" ] ) if self . type in ( "1:1" , "m:1" ) : if len ( current_value ) == 0 : rel_update [ "value" ] = None else : rel_update [ "value" ] = current_value [ 0 ] final . update ( result ) if isinstance ( related_field , BaseTemplateField ) : result_template_field = self . prepare_result_template_field ( result ) final . update ( result_template_field ) for chained_field in self . chained_fields : handler = self . build_handler_from_chained_field ( chained_field ) result = handler . perform ( ) final . update ( result ) return final
Main method of this handler.
Main method of this handler .
"""
        Main method of this handler. It calculates which relation fields have to be updated
        according to the changes in self.field.
        """ # Prepare the new value of our field and the real field name of the reverse field. # We transform everything to lists of fqids to unify the handling. The values are # later transformed back # Just check if we have an invalid use case here. # calculated the fqids which have to be added/remove and partition them by collection # since every collection might have a different related field # acquire all related models with the related fields # again, we transform everything to lists of fqids # calculate actual updates # transform fqids back to ids # remove arrays in *:1 cases which we artificially added # update the reverse template field in the case of a structured field
self