Другое

Как обновлять CSV-файлы в приложениях Todo на Python

Узнайте, как обновлять CSV-файлы при изменении статуса задач в приложениях Todo на Python. Руководство с примерами кода, лучшими практиками и обработкой ошибок.

Как обновить CSV‑файл при изменении статуса задачи в приложении To‑do на Python?

Я разрабатываю приложение To‑do, где детали задач — включая приоритет, статус, оставшееся время до завершения и название задачи — хранятся в CSV‑файле. Когда я обновляю статус задачи в своём коде на Python, соответствующий CSV‑файл не меняется. Вот моя текущая реализация:

python
def mark_task():
    global freetime
    print("You selected Option 5.")
    # Counting the tasks
    count2 = 0
    for i, row in enumerate(mytask):
        count2 += 1
        print(count2, ".", row['task_name'], ".status: ", row['status'])
    task_nam = input("Select the task you want to update: ")
    status = input("Enter status(Pending/Completed): ")
    # Marking tasks
    for i, row in enumerate(mytask):
        if row['task_name'] == task_nam:
            row['status'] = status
            print(f'Status {status} updated for the task {row['task_name']}')
            freetime += 1
            break
        elif row['task_name'] != task_nam:
            print(f"Record Not found in the dictionary {task_nam}")
            break

Как можно изменить этот код, чтобы при обновлении статуса задачи в словаре изменения также отражались в CSV‑файле?

Чтобы обновить CSV‑файл при изменении статуса задачи в вашем приложении «To‑do» на Python, необходимо записать изменённые данные обратно в файл после обновления словаря. В текущем коде список mytask меняется только в памяти, но эти изменения не сохраняются в CSV.

Базовое решение: запись обновлённых данных в CSV

Самый простой способ — после изменения словаря записать обновлённые данные обратно в CSV. Ниже показано, как изменить функцию mark_task():

python
def mark_task():
    global freetime
    print("Вы выбрали пункт 5.")
    # Подсчёт задач
    count2 = 0
    for i, row in enumerate(mytask):
        count2 += 1
        print(count2, ".", row['task_name'], ".status: ", row['status'])
    
    task_nam = input("Выберите задачу, которую хотите обновить: ")
    status = input("Введите статус (Pending/Completed): ")
    
    # Обновление статуса
    task_found = False
    for i, row in enumerate(mytask):
        if row['task_name'] == task_nam:
            row['status'] = status
            print(f'Status {status} updated for the task {row["task_name"]}')
            freetime += 1
            task_found = True
            break
    
    if not task_found:
        print(f"Запись не найдена в словаре {task_nam}")
    else:
        # Запись обновлённых данных в CSV
        write_tasks_to_csv()

Нужна вспомогательная функция для записи в CSV:

python
def write_tasks_to_csv():
    """Записывает обновлённые данные задач обратно в CSV-файл"""
    import csv
    
    # Получаем имена полей из первой строки (предполагается одинаковая структура)
    if mytask:
        fieldnames = mytask[0].keys()
    else:
        return
    
    with open('tasks.csv', 'w', newline='') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(mytask)

Полная реализация с операциями над файлами

Для более надёжного решения рекомендуется использовать временные файлы, чтобы избежать повреждения данных при сбое программы во время записи:

python
from tempfile import NamedTemporaryFile
import csv
import shutil
import os

def mark_task():
    global freetime
    print("Вы выбрали пункт 5.")
    
    # Отображаем задачи
    count2 = 0
    for i, row in enumerate(mytask):
        count2 += 1
        print(count2, ".", row['task_name'], ".status: ", row['status'])
    
    task_nam = input("Выберите задачу, которую хотите обновить: ")
    status = input("Введите статус (Pending/Completed): ")
    
    task_found = False
    for i, row in enumerate(mytask):
        if row['task_name'] == task_nam:
            row['status'] = status
            print(f'Status {status} updated for the task {row["task_name"]}')
            freetime += 1
            task_found = True
            break
    
    if not task_found:
        print(f"Запись не найдена в словаре {task_nam}")
    else:
        # Обновляем CSV с помощью временного файла
        update_csv_with_temp_file('tasks.csv', mytask)

def update_csv_with_temp_file(filename, data):
    """Обновляет CSV, используя временный файл для безопасности"""
    if not data:
        return
    
    fieldnames = data[0].keys()
    
    # Создаём временный файл
    with NamedTemporaryFile(mode='w', newline='', delete=False) as temp_file:
        writer = csv.DictWriter(temp_file, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(data)
        temp_file_path = temp_file.name
    
    # Заменяем оригинальный файл на временный
    try:
        shutil.move(temp_file_path, filename)
        print("CSV файл успешно обновлён!")
    except Exception as e:
        print(f"Ошибка при обновлении CSV: {e}")
        # Удаляем временный файл, если перенос не удался
        if os.path.exists(temp_file_path):
            os.unlink(temp_file_path)

Лучшие практики обновления CSV

При работе с CSV‑файлами в Python учитывайте следующие рекомендации:

  1. Используйте временные файлы – это защищает от повреждения данных, если программа аварийно завершится во время записи.
  2. Обрабатывайте пути к файлам корректно – используйте абсолютные пути или убедитесь, что CSV находится в правильной рабочей директории.
  3. Проверяйте структуру данных – убедитесь, что все строки имеют одинаковую структуру перед записью.
  4. Добавьте обработку ошибок – включите исключения для операций с файлами.
  5. Учитывайте производительность – при больших файлах чтение‑модификация‑запись может быть медленной. Для больших наборов данных рассмотрите использование базы данных.

Ниже пример с более надёжной обработкой ошибок:

python
def safe_update_csv(filename, data):
    """Надёжно обновляет CSV с полной обработкой ошибок"""
    if not data:
        print("Нет данных для записи в CSV")
        return False
    
    try:
        # Проверяем структуру данных
        fieldnames = data[0].keys()
        for row in data:
            if set(row.keys()) != set(fieldnames):
                raise ValueError("Несогласованная структура данных в строках")
        
        # Создаём временный файл
        with NamedTemporaryFile(mode='w', newline='', delete=False) as temp_file:
            writer = csv.DictWriter(temp_file, fieldnames=fieldnames)
            writer.writeheader()
            writer.writerows(data)
            temp_file_path = temp_file.name
        
        # Заменяем оригинальный файл
        shutil.move(temp_file_path, filename)
        return True
        
    except ValueError as ve:
        print(f"Ошибка проверки данных: {ve}")
        return False
    except csv.Error as csv_e:
        print(f"Ошибка записи CSV: {csv_e}")
        if 'temp_file_path' in locals() and os.path.exists(temp_file_path):
            os.unlink(temp_file_path)
        return False
    except Exception as e:
        print(f"Неожиданная ошибка при обновлении CSV: {e}")
        if 'temp_file_path' in locals() and os.path.exists(temp_file_path):
            os.unlink(temp_file_path)
        return False

Альтернативные подходы

Использование библиотеки pandas

Для более сложных операций рассмотрите pandas:

python
import pandas as pd

def mark_task_with_pandas():
    """Обновляет статус задачи с помощью pandas"""
    task_nam = input("Выберите задачу, которую хотите обновить: ")
    status = input("Введите статус (Pending/Completed): ")
    
    # Читаем CSV в DataFrame
    df = pd.read_csv('tasks.csv')
    
    # Находим и обновляем задачу
    mask = df['task_name'] == task_nam
    if mask.any():
        df.loc[mask, 'status'] = status
        # Сохраняем обратно в CSV
        df.to_csv('tasks.csv', index=False)
        print(f'Status {status} updated for the task {task_nam}')
        return True
    else:
        print(f"Задача {task_nam} не найдена")
        return False

Использование OrderedDict для сохранения порядка

Если нужно сохранить исходный порядок строк CSV:

python
from collections import OrderedDict

def update_csv_with_ordered_dict(filename, data):
    """Обновляет CSV, сохраняя порядок строк"""
    fieldnames = data[0].keys()
    
    with NamedTemporaryFile(mode='w', newline='', delete=False) as temp_file:
        writer = csv.DictWriter(temp_file, fieldnames=fieldnames)
        writer.writeheader()
        
        # Записываем строки в исходном порядке
        for row in data:
            writer.writerow(OrderedDict((k, row[k]) for k in fieldnames))
        
        temp_file_path = temp_file.name
    
    shutil.move(temp_file_path, filename)

Обработка ошибок и надёжность

Для готового к продакшн кода включите всестороннюю обработку ошибок:

python
def robust_mark_task():
    """Надёжное обновление статуса задачи с полной обработкой ошибок"""
    global freetime
    
    try:
        print("Вы выбрали пункт 5.")
        
        # Проверяем наличие задач
        if not mytask:
            print("Нет доступных задач")
            return
        
        # Отображаем задачи с обработкой ошибок
        try:
            count2 = 0
            for i, row in enumerate(mytask):
                count2 += 1
                print(count2, ".", row['task_name'], ".status: ", row['status'])
        except KeyError as ke:
            print(f"Отсутствует ожидаемое поле в данных задачи: {ke}")
            return
        
        # Получаем ввод пользователя с проверкой
        task_nam = input("Выберите задачу, которую хотите обновить: ").strip()
        if not task_nam:
            print("Имя задачи не может быть пустым")
            return
        
        status = input("Введите статус (Pending/Completed): ").strip()
        if status not in ['Pending', 'Completed']:
            print("Неверный статус. Пожалуйста, введите 'Pending' или 'Completed'")
            return
        
        # Находим и обновляем задачу
        task_found = False
        for i, row in enumerate(mytask):
            try:
                if row['task_name'] == task_nam:
                    row['status'] = status
                    print(f'Status {status} updated for the task {row["task_name"]}')
                    freetime += 1
                    task_found = True
                    break
            except KeyError:
                print(f"Задача на позиции {i} имеет отсутствующие обязательные поля")
                continue
        
        if not task_found:
            print(f"Запись не найдена в словаре {task_nam}")
        else:
            # Обновляем CSV
            if safe_update_csv('tasks.csv', mytask):
                print("Статус задачи обновлён и сохранён успешно!")
            else:
                print("Предупреждение: задача обновлена в памяти, но не удалось сохранить в CSV")
    
    except KeyboardInterrupt:
        print("\nОперация отменена пользователем")
    except Exception as e:
        print(f"Неожиданная ошибка в mark_task: {e}")

Вывод

Чтобы обновлять CSV‑файл при изменении статуса задачи в вашем приложении «To‑do» на Python:

  1. Всегда записывайте изменения обратно в CSV после обновления данных в памяти.
  2. Используйте временные файлы для безопасного обновления, чтобы избежать повреждения данных.
  3. Включайте надёжную обработку ошибок при работе с файлами.
  4. Рассмотрите pandas для более сложных операций с CSV.
  5. Проверяйте ввод пользователя для сохранения целостности данных.

Ключевое улучшение вашего текущего кода – добавить функцию, которая записывает обновлённый список mytask обратно в CSV. Рекомендуемый подход с временным файлом обеспечивает безопасность и надёжность при работе с файлами.

Авторы
Проверено модерацией
Модерация