async def create_or_update(row: Dict, model_id: Text) -> Tuple: try: model_data = cfg.models[model_id] row = prepare_request_params(row, model_id, model_data) obj = (await model_data["model"].create(**row)).to_dict() obj_id = get_obj_id_from_row(model_data, obj) return obj_id, None, None except asyncpg.exceptions.UniqueViolationError as e: if cfg.csv_update_existed: obj_id = prepare_request_params( get_obj_id_from_row(model_data, row), model_id, model_data) obj = await get_by_params(obj_id, model_data["model"]) await obj.update(**row).apply() return None, obj_id, None else: return None, None, (row, e.args) except Exception as e: return None, None, (row, e.args)
async def model_edit_post(request, model_id): model_data = cfg.models[model_id] model = model_data["model"] columns_data = model_data["columns_data"] previous_id: Dict = utils.extract_obj_id_from_query( dict(request.query_args)["_id"]) previous_id: Dict = utils.correct_types(previous_id, columns_data, no_default=True) request_params = { key: request.form[key][0] if request.form[key][0] != "None" else None for key in request.form } request_params = utils.prepare_request_params(request_params, model_id, model_data) try: if not model_data["identity"]: old_obj = previous_id await update_all_by_params(request_params, previous_id, model) obj = request_params else: obj = await get_by_params(previous_id, model) old_obj = obj.to_dict() await obj.update(**request_params).apply() obj = obj.to_dict() changes = utils.get_changes(old_obj, obj) new_obj_id = utils.get_obj_id_from_row(model_data, request_params, previous_id) message = f"Object with id {previous_id} was updated." if changes: message += f'Changes: from {changes["from"]} to {changes["to"]}' request.ctx.flash(message, "success") log_history_event(request, message, previous_id) except asyncpg.exceptions.ForeignKeyViolationError as e: request.ctx.flash( f"ForeignKey error. " f"Impossible to edit field for row {previous_id}, " f"because exists objects that depend on it. {e}", "error", ) except asyncpg.exceptions.UniqueViolationError: request.ctx.flash( f"{model_id.capitalize()} with such id already exists", "error") except asyncpg.exceptions.NotNullViolationError as e: column = e.args[0].split("column")[1].split("violates")[0] request.ctx.flash(f"Field {column} cannot be null", "error") return await render_add_or_edit_form(request, model_id, new_obj_id)
async def model_add(request, model_id): model_data = cfg.models[model_id] request_params = {key: request.form[key][0] for key in request.form} request_params = utils.prepare_request_params(request_params, model_id, model_data) not_filled = [ x for x in model_data["required_columns"] if x not in request_params ] if not_filled: request.ctx.flash(f"Fields {not_filled} required. Please fill it", "error") else: try: obj = await model_data["model"].create(**request_params) obj_id = utils.get_obj_id_from_row(model_data, obj.to_dict()) message = f"Object with {obj_id} was added." request.ctx.flash(message, "success") log_history_event(request, message, obj_id) except ( asyncpg.exceptions.StringDataRightTruncationError, ValueError, asyncpg.exceptions.ForeignKeyViolationError, ) as e: request.ctx.flash(e.args, "error") except asyncpg.exceptions.UniqueViolationError: request.ctx.flash( f"{model_id.capitalize()} with such id already exists", "error") except asyncpg.exceptions.NotNullViolationError as e: column = e.args[0].split("column")[1].split("violates")[0] request.ctx.flash(f"Field {column} cannot be null", "error") except asyncpg.exceptions.UndefinedTableError: request.ctx.flash( f"Somebody stole the table. Table {model_id} does not exist", "error") return await render_add_or_edit_form(request, model_id)
async def upload_composite_csv_row(row, header, tables_indexes, stack, unique_keys): # if composite header each column == {'table': {}, 'column': None} # todo: refactor this huge code table_num = 0 previous_table_name = None id_added = [] id_updated = [] for table_name, indexes in tables_indexes.items(): # {'start': None, 'end': None} table_header = deepcopy(header)[indexes["start"]:indexes["end"] + 1 # noqa E203 ] table_row_data = deepcopy(row)[indexes["start"]:indexes["end"] + 1 # noqa E203 ] if not any(table_row_data): if table_header[0]["table"][0] == table_header[0]["table"][1]: previous_table_name = table_name else: for elem in stack[::-1]: if elem in table_header[0]["table"][1]: previous_table_name = elem break table_num += 1 continue if table_header[0]["table"][0] == table_header[0]["table"][1]: model_id = table_name columns_data = cfg.models[model_id]["columns_data"] else: model_id = None columns_indexes_remove = [] for index, field_value in enumerate(table_header): if isinstance(field_value["column"], CompositeType): model_id = table_row_data[index] table_row_data.pop(index) break if model_id: table_header.pop(index) else: model_id = cfg.composite_csv_settings[table_name][ "pattern"].replace("*", previous_table_name) columns_data = cfg.models[model_id]["columns_data"] for index, value in enumerate(table_header): if value["column"] not in columns_data: # column not in this table columns_indexes_remove.append(index) for num, index in enumerate(columns_indexes_remove): table_header.pop(index - num) table_row_data.pop(index - num) table_row = { table_header[num]["column"]: value for num, value in enumerate(table_row_data) } model_data = cfg.models[model_id] try: table_row = prepare_request_params(table_row, model_id, model_data) if table_num > 0: column, target_column = cfg.models[model_id]["foreign_keys"][ previous_table_name] foreing_column_value = unique_keys[previous_table_name][ target_column] table_row[column] = foreing_column_value id_added, id_updated, error = await create_or_update( table_row, model_id) if id_added or id_updated: id_ = id_added if id_added else id_updated new_obj = (await get_by_params(id_, model_data["model"])).to_dict() if indexes["start"] == 0: unique_keys = {} unique_keys[model_id] = new_obj stack.append(model_id) previous_table_name = model_id table_num += 1 else: return None, id_updated, error, stack, unique_keys except Exception as e: return None, None, (table_row, e), stack, unique_keys # TODO: right now just abort if error during composite file upload return id_added, id_updated, None, stack, unique_keys
async def upload_simple_csv_row(row, header, model_id): row = {header[index]: value for index, value in enumerate(row)} row = prepare_request_params(row, model_id, cfg.models[model_id]) return await create_or_update(row, model_id)