Volver al inicio

CRUD en Python: crear un gestor de tareas con Tkinter y JSON

Guía práctica para implementar operaciones CRUD en Python creando un gestor de tareas de escritorio. El artículo cubre el trabajo con Tkinter para construir una interfaz gráfica, el uso de JSON para el almacenamiento de datos y los conceptos básicos de la programación orientada a objetos.

Creación de una aplicación CRUD en Python: gestor de tareas desde cero
Advertisement 728x90

# Guía práctica de CRUD: Crea un gestor de tareas con Python y Tkinter

CRUD (Crear, Leer, Actualizar, Eliminar) es un patrón fundamental para operaciones con datos. En esta guía, lo pondremos en práctica construyendo un gestor de tareas de escritorio con Python, Tkinter y JSON para el almacenamiento de datos. Ideal para desarrolladores que quieran reforzar conceptos básicos de POO, manejo de archivos y desarrollo de interfaces gráficas.

Arquitectura de la app y configuración

Nuestra app vivirá en un único archivo app.py. Usaremos JSON para el almacenamiento de datos: simple y directo para este tipo de proyecto. Cada tarea es un diccionario con id (identificador único), text (descripción) y completed (estado). Todas las tareas se guardan en una lista, serializada en tasks.json.

Asegúrate de tener Python 3.6 o superior instalado. Tkinter viene incluido, así que no necesitas instalaciones extras. Crea una carpeta para el proyecto y ábrela en tu IDE.

Google AdInline article slot

Modelo de datos y manejo de JSON

Primero, implementaremos funciones para cargar y guardar datos: la base para las operaciones Leer y Actualizar de CRUD.

import json
import os

TASKS_FILE = "tasks.json"

def load_tasks():
    """Carga las tareas desde el archivo JSON."""
    if not os.path.exists(TASKS_FILE):
        return []
    with open(TASKS_FILE, "r", encoding="utf-8") as f:
        try:
            return json.load(f)
        except json.JSONDecodeError:
            return []

def save_tasks(tasks):
    """Guarda la lista de tareas en el archivo JSON."""
    with open(TASKS_FILE, "w", encoding="utf-8") as f:
        json.dump(tasks, f, ensure_ascii=False, indent=2)

def get_next_id(tasks):
    """Genera el siguiente ID único para una nueva tarea."""
    if not tasks:
        return 1
    return max(task["id"] for task in tasks) + 1

Características clave:

  • load_tasks maneja archivos inexistentes o corruptos con gracia.
  • ensure_ascii=False en json.dump asegura soporte adecuado para Unicode.
  • indent=2 mantiene el JSON legible.

Construyendo la interfaz con Tkinter

Crearemos una clase TodoApp para gestionar la ventana principal y los widgets. La interfaz incluye:

Google AdInline article slot
  • Campo de entrada para nuevas tareas.
  • Listbox para mostrar todas las tareas.
  • Botones de control: agregar, marcar como hecho, eliminar.
import tkinter as tk
from tkinter import messagebox

class TodoApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Gestor de Tareas")
        self.root.geometry("500x400")
        self.root.resizable(False, False)
        self.tasks = load_tasks()
        self.create_widgets()
        self.refresh_task_list()

    def create_widgets(self):
        """Configura todos los elementos de la UI."""
        # Panel superior: entrada y botón agregar
        top_frame = tk.Frame(self.root)
        top_frame.pack(pady=10, padx=10, fill=tk.X)
        self.entry = tk.Entry(top_frame, font=("Arial", 12))
        self.entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
        self.entry.bind("<Return>", lambda event: self.add_task())
        self.add_button = tk.Button(top_frame, text="➕ Agregar", command=self.add_task)
        self.add_button.pack(side=tk.RIGHT)
        # Lista de tareas con scrollbar
        list_frame = tk.Frame(self.root)
        list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        scrollbar = tk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.task_listbox = tk.Listbox(
            list_frame,
            font=("Arial", 11),
            yscrollcommand=scrollbar.set,
            selectmode=tk.SINGLE,
            height=15
        )
        self.task_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.task_listbox.yview)
        # Panel inferior: botones de acción
        bottom_frame = tk.Frame(self.root)
        bottom_frame.pack(pady=10, padx=10, fill=tk.X)
        self.done_button = tk.Button(bottom_frame, text="✅ Hecho", command=self.mark_done)
        self.done_button.pack(side=tk.LEFT, padx=5)
        self.delete_button = tk.Button(bottom_frame, text="🗑 Eliminar", command=self.delete_task)
        self.delete_button.pack(side=tk.LEFT, padx=5)
        self.exit_button = tk.Button(bottom_frame, text="Salir", command=self.root.quit)
        self.exit_button.pack(side=tk.RIGHT, padx=5)

    def refresh_task_list(self):
        """Actualiza la visualización de la lista de tareas."""
        self.task_listbox.delete(0, tk.END)
        for task in self.tasks:
            status = "✓" if task["completed"] else "○"
            display_text = f"{status} {task['id']}. {task['text']}"
            self.task_listbox.insert(tk.END, display_text)

refresh_task_list maneja la operación Leer, mostrando el estado actual de los datos. Las marcas (✓/○) visualizan el estado de completado.

Implementando operaciones CRUD

A continuación, agrega métodos a la clase para las acciones del usuario, cada uno ligado a una operación CRUD.

Crear: Agregar una nueva tarea

    def add_task(self):
        """Agrega una nueva tarea (Crear)."""
        text = self.entry.get().strip()
        if not text:
            messagebox.showwarning("Advertencia", "Introduce el texto de la tarea")
            return
        next_id = get_next_id(self.tasks)
        new_task = {
            "id": next_id,
            "text": text,
            "completed": False
        }
        self.tasks.append(new_task)
        save_tasks(self.tasks)
        self.entry.delete(0, tk.END)
        self.refresh_task_list()
        messagebox.showinfo("Éxito", f"Tarea agregada (ID: {next_id})")

Actualizar: Marcar tarea como hecha

    def mark_done(self):
        """Marca la tarea seleccionada como hecha (Actualizar)."""
        selection = self.task_listbox.curselection()
        if not selection:
            messagebox.showwarning("Advertencia", "Selecciona una tarea")
            return
        index = selection[0]
        task_id = self.tasks[index]["id"]
        for task in self.tasks:
            if task["id"] == task_id:
                if task["completed"]:
                    messagebox.showinfo("Info", "La tarea ya está hecha")
                else:
                    task["completed"] = True
                    save_tasks(self.tasks)
                    self.refresh_task_list()
                    messagebox.showinfo("Éxito", f"Tarea #{task_id} marcada como hecha")
                return

Eliminar: Quitar una tarea

    def delete_task(self):
        """Elimina la tarea seleccionada (Eliminar)."""
        selection = self.task_listbox.curselection()
        if not selection:
            messagebox.showwarning("Advertencia", "Selecciona una tarea")
            return
        index = selection[0]
        task_id = self.tasks[index]["id"]
        task_text = self.tasks[index]["text"]
        if messagebox.askyesno("Confirmar", f"¿Eliminar tarea #{task_id} \"{task_text}\"?"):
            del self.tasks[index]
            save_tasks(self.tasks)
            self.refresh_task_list()
            messagebox.showinfo("Éxito", f"Tarea #{task_id} eliminada")

Cada método valida la entrada, actualiza los datos en memoria, guarda en archivo y refresca la UI. Los messagebox proporcionan retroalimentación clara al usuario.

Google AdInline article slot

Ensamblando y ejecutando la app

Une todo en un archivo con un punto de entrada principal.

if __name__ == "__main__":
    root = tk.Tk()
    app = TodoApp(root)
    root.mainloop()

Ejecuta con python app.py. Prueba todas las operaciones CRUD: la app guarda los datos en tasks.json entre sesiones.

Lecciones clave

  • Fundamentos de CRUD: Crear, Leer, Actualizar, Eliminar impulsa la mayoría de apps con datos.
  • Almacenamiento JSON: Ideal para proyectos pequeños, sin necesidad de base de datos.
  • Interfaz Tkinter: UIs de escritorio rápidas, multiplataforma y sin dependencias.
  • Estructura de código limpia: Separa modelo de datos (JSON), vista (Tkinter) y lógica (TodoApp) para fácil mantenimiento.
  • Manejo de errores: Valida entradas y captura problemas como JSON defectuoso.

Pasos siguientes

Expande tu gestor de tareas:

  • Categorías de tareas con filtros.
  • Fechas límite usando datetime y codificación por colores.
  • Exportar a CSV o Excel.
  • Integración con base de datos (SQLite, PostgreSQL).
  • Versión web con Flask o Django.

Este proyecto muestra cómo los conceptos básicos de programación se aplican a apps del mundo real, construyendo una base sólida para temas avanzados.

— Editorial Team

Advertisement 728x90

Leer después