Как обновлять QtableView новыми данными с сохранением всех настроек (делегаты в ячейках, заливка ячеек и так далее)?

У меня есть код на PyQt5, в котором есть QTableView, содержащий множество свойств. Я хочу сделать так, чтобы экземпляр этого класса можно было обновлять посредством нового df pandas. Как это сделать? Прилагаю малую часть кода. Также в Table_widget приведена только часть функций

class Table_widget(QTableView):
    def __init__(
            self,
            table_name: str= None,
            df: Union[pd.DataFrame, QStandardItemModel, str]= None,
            columns_index: list= None,
            columns_width: list= None,
            visible_horizont_header: bool= True,
            visible_vertical_header: bool= False,
            name_columns_by_df: bool= True,
            show_button_filter: bool= False,
            columns_non_editable: list= None,
            path_save_to_Data_lake: Union[bool, str]= None,
            column_condition= str,
            condition: str= None,
            path_picture_condition: str= None,
            count_frozen_columns: int= 0,
            show_grid: bool= True,
            table_style: str= 'Без_стиля',
            level_1_table: list= None,
            wrap_cells: list= None,
            button_add_row_or_column: bool= False,
            visible_horizontal_scroll: bool= True,
            visible_vertical_scroll: bool= True,
            path_scroll_position: str= None,
            max_undo_steps: int= 80,
            list_total_rows: list= None,
            formulas_and_cells: list= None,
            auto_recalculation_formulas: bool= True):
        super().__init__()
        self.table_name = table_name
        self.df = df
        self.columns_index = columns_index
        self.show_button_filter = show_button_filter
        self.columns_non_editable = columns_non_editable
        self.path_save_to_Data_lake = path_save_to_Data_lake
        self.count_frozen_columns = count_frozen_columns
        self.table_style = table_style
        self.level_1_table = level_1_table  # Cтолбц первого уровня сводного вида
        self.path_scroll_position = path_scroll_position
        self.max_undo_steps = max_undo_steps
        self.list_total_rows = list_total_rows
        self.border_delegate = None
        self.delegate_for_columns = {}
        self.shared_delegate = Custom_delegate(self)
        
        # Установка модели
        self.table_model = self.create_table_model(
            self.df,
            path_picture_condition,
            column_condition, condition,
            name_columns_by_df)
        
        self.setModel(self.table_model)

        if columns_index == None:
            columns_index = []
        
        # Закрепление левого столбца
        if self.count_frozen_columns > 0:
            self.count_frozen_columns += len(columns_index)
            self.frozen_table = QTableView(self)
            self.frozen_table.setModel(self.table_model)
            self.setHorizontalScrollMode(
                self.ScrollMode.ScrollPerPixel)
            self.frozen_table.horizontalHeader().setVisible(
                visible_horizont_header)
            self.frozen_table.horizontalHeader().setSectionResizeMode(
                QHeaderView.ResizeMode.Fixed)               
            self.frozen_table.setVerticalHeader(
                self.vertical_header(
                    Qt.Orientation.Vertical,
                    button_add_row_or_column,
                    self))
            self.frozen_table.verticalHeader().setVisible(
                visible_vertical_header)
            for column in range(
                0, len(columns_index)):
                    self.frozen_table.setColumnHidden(column, True)
            for column in range(
                self.count_frozen_columns, len(df.columns)):
                    self.frozen_table.setColumnHidden(column, True)
            self.frozen_table.scale_factor = 100
            self.frozen_table.setSelectionModel(
                self.selectionModel())
            if columns_width != None:  # Ширина столбцов
                for column in columns_width:
                    self.frozen_table.setColumnWidth(
                        column[0]+len(columns_index),
                        column[1])
            self.frozen_table.setHorizontalScrollBarPolicy(
                Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
            self.frozen_table.setVerticalScrollBarPolicy(
                Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
            self.frozen_table.setVerticalScrollMode(
                self.ScrollMode.ScrollPerPixel)
            self.frozen_table.verticalScrollBar().valueChanged.connect(
                self.verticalScrollBar().setValue)
            self.frozen_table.setShowGrid(show_grid)
            self.frozen_table.show()
            self.update_frozen_TableGeometry()
            self.viewport().stackUnder(
                self.frozen_table)
            self.horizontalHeader().sectionResized.connect(
                self.update_section_width)
            self.verticalHeader().sectionResized.connect(
                self.update_section_height)
            self.verticalScrollBar().valueChanged.connect(
                self.frozen_table.verticalScrollBar().setValue)
            for column in self.columns_non_editable:
                self.frozen_table.setItemDelegateForColumn(
                    column, non_column_delegate)

        # Настройка таблицы
        self.horizontalHeader().setVisible(
            visible_horizont_header)
        self.horizontal_header_ = self.horizontal_header(
            QT_layout_horizontal, self.df,
            button_add_row_or_column, self)
        self.setHorizontalHeader(
            self.horizontal_header_)  # Настройка горизонтальных заголовков таблицы
        self.setHorizontalScrollMode(
            self.ScrollMode.ScrollPerPixel)
        self.setVerticalScrollMode(
            self.ScrollMode.ScrollPerPixel)
        self.installEventFilter(self)
        self.show_buttons_filter(
            self.show_button_filter)
        self.setVerticalHeader(
            self.vertical_header(
                Qt.Orientation.Vertical,
                button_add_row_or_column,
                self))
        self.verticalHeader().setVisible(
            visible_vertical_header)
        for column in range(0, len(columns_index)):
            self.setColumnHidden(column, True)
        self.scale_factor = 100  # Масштабирование (приближение и отдаление) - установка начального значения
        self.selected_index = None  # Переменная для хранения выбранного индекса
        self.delegates_for_columns = {}  # Словарь для хранения делегатов (нужно на случай, когда делегаты в нескольких столбцах)
        self.undo_stack = []
        self.data_cut = None  # Хранение вырезанных данных (для шорткатов)
        self.is_cut = False    # Флаг, указывающий, вырезано ли что-либо (для шорткатов)
        self.table_styling(table_style)
        self.show_grid(show_grid)
        self.cell_style()
        if wrap_cells is not None:  # Перенос текста
            self.word_wrap(wrap_cells)
            self.model().dataChanged.connect(
                lambda: self.word_wrap(wrap_cells))
        if columns_width != None:  # Установка ширины столбцов
            for column in columns_width:
                self.setColumnWidth(
                    column[0]+len(columns_index),
                    column[1])
        for column in self.columns_non_editable:  # Нередактируемые столбцы
            self.setItemDelegateForColumn(
                column, non_column_delegate)
        # if list_total_rows != None:
        #     self.add_total_row(list_total_rows)    # Этот код нужно доработать, строка "Итого" в виде отдельной таблицы не раюотает
        if self.path_scroll_position != None:
            self.load_scroll_position()
        self.vertical_scroll_bar(
            visible_vertical_scroll)
        self.horizontal_scroll_bar(
            visible_horizontal_scroll)
        
        # Сигналы для работы формул таблицы
        self.formula_history = {}  # Словарь для хранения формул, вбитых в ячейки
        
        if formulas_and_cells != None:  # Инициализация формул, если они переданы
            self.initialize_formulas(formulas_and_cells)
            self.doubleClicked.connect(
                lambda: self.display_formula_in_active_cell())
            
        if auto_recalculation_formulas:
            self.table_model.dataChanged.connect(
                lambda: self.auto_calculation_formulas())
        
        # Сохранение измененной таблицы в БД
        self._save_timer = None
        if path_save_to_Data_lake is not False:
            self.model().dataChanged.connect(
                lambda: self.save_table_to_Data_lake(
                    path_save_to_Data_lake))
            
    def create_table_model(
            self, df,
            path_picture_condition: str= None,
            column_condition: int= None,
            condition: str= None,
            name_columns_by_df: bool= True):
        if isinstance(df, QStandardItemModel):
            table_model = df
            return table_model
        
        elif isinstance(df, str):
            return self.create_table_from_excel(df)

        table_model = QStandardItemModel()

        if name_columns_by_df == True:
            list_columns = list(df.columns)
            table_model.setHorizontalHeaderLabels(list_columns)

        for row in range(df.shape[0]):  # Заполнение модели данными из датафрейма
            for col in range(df.shape[1]):
                if path_picture_condition is not None \
                and df.iloc[row, column_condition] == condition \
                and col == column_condition:
                    item = QStandardItem()
                    item.setIcon(QIcon(path_picture_condition))

                elif path_picture_condition is not None \
                and df.iloc[row, column_condition] != condition \
                and col == column_condition:
                    item = QStandardItem('')

                else:
                    item = QStandardItem(str(df.iloc[row, col]))

                table_model.setItem(row, col, item)

        return table_model

    def create_table_from_excel(self, file_path):
        '''Создание таблицы эксель из файла xlsx'''
        wb = dl.read_excel(file_path)
        ws = wb.active
        table_model = QStandardItemModel(
            ws.max_row, ws.max_column)

        occupied_cells = set()  # Множество для отслеживания занятых ячеек
        merged_cells = list(ws.merged_cells.ranges)
        enumerate_iter_rows = ws.iter_rows(
            min_row= 1, max_row= ws.max_row,
            min_col= 1, max_col= ws.max_column)
        for i, row in enumerate(enumerate_iter_rows):
            for j, cell in enumerate(row):
                if (i, j) in occupied_cells:
                    continue  # Пропустить, если ячейка уже занята

                col_coordinate = cell.coordinate
                if any(col_coordinate in merged_range \
                for merged_range in merged_cells):
                    for merged_range in merged_cells:
                        if col_coordinate in merged_range:
                            start_col, start_row, end_col, end_row \
                                = merged_range.bounds
                            count_row_span = end_row - start_row + 1
                            count_col_span = end_col - start_col + 1
                            if all((row_idx, col_idx) not in occupied_cells 
                            for row_idx in range(i, i + count_row_span) 
                            for col_idx in range(j, j + count_col_span)):  # Объединение только незананятых ячеек
                                self.setSpan(
                                    i, j, count_row_span, count_col_span)
                                for row_idx in range(i, i + count_row_span):  # Добавление занятых ячеек в множество
                                    for col_idx in range(j, j + count_col_span):
                                        occupied_cells.add((row_idx, col_idx))
                
                table_item = QStandardItem(str(cell.value))

                if cell.font.bold:
                    table_item.setFont(QFont('', -1, QFont.Weight.Bold))

                if cell.alignment.horizontal == "center":
                    table_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)

                table_model.setItem(i, j, table_item)
                
                # Установка ширины столбцов виджета в соответствии с шириной колонки в эксель
                letter = get_column_letter(j + 1)
                column_width = ws.column_dimensions[letter].width
                self.setColumnWidth(j, int(column_width * 15))

        for i in range(table_model.rowCount()):
            self.resizeRowToContents(i)

        return table_model

    def setData(self, index, value):
        item = self.table_model.itemFromIndex(index)
        if item is not None:
            old_data = item.text()  # Сохранение старого значения
            self.undo_stack.append((index, old_data))  # Добавление в стек отмены
            if self.max_undo_steps != None \
            and len(self.undo_stack) > self.max_undo_steps:  # Проверка, превышает ли размер стека максимальное количество шагов
                self.undo_stack.pop(0)  # Удаление самого старого элемента
            item.setText(value)  # Установление нового значения

    def border_table(
            self, target_row, target_column,
            table_border_mode, line_thickness, color):
        target_column = target_column \
            if isinstance(target_column, list) \
            else [target_column]
        target_column = target_column \
            + self.columns_index

        self.shared_delegate.configure_for_border({
            'mode': table_border_mode,
            'target_row': target_row,
            'target_column': target_column,
            'color': color,
            'line_thickness': line_thickness})
        self.setItemDelegate(self.shared_delegate)

    def delegate_for_column(self, column, regex, mask):
        delegate = Custom_delegate(self)
        delegate.configure_for_mask(regex, mask)
        column = column + len(self.columns_index)
        self.setItemDelegateForColumn(column, delegate)

        if hasattr(self, 'frozen_table'):
            self.frozen_table.setItemDelegateForColumn(
                column, delegate)
        
        # Сохранение кажого делегата в словарь 
        # Это чтобы у каждого столбцы был свой делегат
        self.delegate_for_columns[column] = delegate

Вот экземпляр класса. Как сделать так, чтобы передал в экземпляр новый df_residents и всё обновилось, но свойства сохранились? Я пытался сделать через повторный вызов модели, в которую передаю df_residents и это сработало - виджет обновился новыми данными, но вот все свойства, настроенные функциями, стёрлись

self.table_residents = Table_widget(
    df= df_residents,
    columns_width= [
        [0, 50], [1, 540], [2, 120],
        [3, 170], [4, 120], [5, 120],
        [6, 180], [7, 180], [8, 180],
        [9, 220], [10, 110]],
    columns_index= ['ID_resident', 'ID_house'],
    visible_horizont_header= True,
    visible_vertical_header= False,
    name_columns_by_df= True,
    show_button_filter= True,
    columns_non_editable= [0],
    path_save_to_Data_lake= \
        path_df_residents,
    column_condition= None,
    condition= None,
    path_picture_condition= None,
    count_frozen_columns= 1,
    level_1_table= ['№ кв'],
    show_grid= True,
    table_style= 'Стиль_Синий_заголовок',
    wrap_cells= None,
    button_add_row_or_column= False,
    path_scroll_position= \
        f'{path_Tab_receipts}{house_name}',
    max_undo_steps= 50)
self.table_residents.setFixedSize(1292, 980)  # Ширина, высота
self.table_residents.delegate_for_column(
    2,
    '\\,d{2}\\.\\d{2}\\.\\d{4}',
    '31.07.8888')
self.table_residents.delegate_for_column(
    4,
    '\\d{2}\\.\\d{2}\\.\\d{4}',
    '31.07.8888')
self.table_residents.delegate_for_column(
    5,
    '\\d{2}\\.\\d{2}\\.\\d{4}',
    '31.07.8888')
self.table_residents.delegate_for_column(
    8,
    '\\d{1}\\(\\d{3}\\)\\d{3}-\\d{2}-\\d{2}',
    '0(000)000-00-00')

Ответы (0 шт):