def create(self, validated_data, **kwargs):
        """Create a new column."""
        # Preliminary checks
        data_type = validated_data.get('data_type')
        if (data_type is None
                or data_type not in list(pandas_datatype_names.values())):
            # The data type is not legal
            raise Exception(_('Incorrect data type {0}.').format(data_type))

        column_obj = None
        try:
            # Create the object, but point to the given workflow
            column_obj = Column(
                name=validated_data['name'],
                description_text=validated_data.get('description_text', ''),
                workflow=self.context['workflow'],
                data_type=data_type,
                is_key=validated_data.get('is_key', False),
                position=validated_data.get('position', 0),
                in_viz=validated_data.get('in_viz', True),
                active_from=validated_data.get('active_from'),
                active_to=validated_data.get('active_to'),
            )

            # Set the categories if they exists
            column_obj.set_categories(validated_data.get('categories', []),
                                      True)

            if (column_obj.active_from and column_obj.active_to
                    and column_obj.active_from > column_obj.active_to):
                raise Exception(
                    _('Incorrect date/times in the active window for ' +
                      'column {0}').format(validated_data['name']))

            # All tests passed, proceed to save the object.
            column_obj.save()
        except Exception as exc:
            if column_obj:
                column_obj.delete()
            raise exc

        return column_obj
Exemple #2
0
def delete_column(
    user: get_user_model(),
    workflow: models.Workflow,
    column: models.Column,
    cond_to_delete: Optional[List[models.Condition]] = None,
):
    """Remove column from ontask.workflow.

    Given a workflow and a column, removes it from the workflow (and the
    corresponding data frame

    :param user: User performing the operation
    :param workflow: Workflow object
    :param column: Column object to delete
    :param cond_to_delete: List of conditions to delete after removing the
    column
    :return: Nothing. Effect reflected in the database
    """
    column.log(user, models.Log.COLUMN_DELETE)

    # Drop the column from the DB table storing the data frame
    sql.df_drop_column(workflow.get_data_frame_table_name(), column.name)

    # Reposition the columns above the one being deleted
    workflow.reposition_columns(column.position, workflow.ncols + 1)

    # Delete the column
    column.delete()

    # Update the information in the workflow
    workflow.ncols = workflow.ncols - 1
    workflow.save()

    if not cond_to_delete:
        # The conditions to delete are not given, so calculate them
        # Get the conditions/actions attached to this workflow
        cond_to_delete = [
            cond for cond in models.Condition.objects.filter(
                action__workflow=workflow) if column in cond.columns.all()
        ]

    # If a column disappears, the conditions that contain that variable
    # are removed
    actions_without_filters = []
    for condition in cond_to_delete:
        if condition.is_filter:
            actions_without_filters.append(condition.action)

        # Formula has the name of the deleted column. Delete it
        condition.delete()

    # Traverse the actions for which the filter has been deleted and reassess
    #  all their conditions
    # TODO: Explore how to do this asynchronously (or lazy)
    for act in actions_without_filters:
        act.update_n_rows_selected()

    # If a column disappears, the views that contain only that column need to
    # disappear as well as they are no longer relevant.
    for view in workflow.views.all():
        if view.columns.count() == 0:
            view.delete()