📊 Aprende a crear Aplicaciones Flask usando CRUD – Tutorial (Parte 3)

Aprende a crear Aplicaciones Flask usando CRUD – Tutorial (Parte 3)

Bienvenidos a Aplicaciones Flask Web [Parte 3]: CRUD Completo. En esta tercera parte vamos a implementar todas las operaciones de gestión de datos (CRUD) en nuestro modelo para tenerlo 100% funcional y listo para conectar con el controlador.

 

En este post aprenderás a crear métodos para crear, leer, actualizar y borrar registros (CRUD) facilitando así la gestión de tu base de datos, que en este caso utilizamos JSON por la facilidad de trabajarla como si fuera un diccionario.

Aprendida esta estructura recuerda utilizarla siempre en tus aplicaciones sea que trabajen con bases de datos relacionales o no relacionales y por más pequeña que sea la aplicación o apenas se trate de leer un txt. Es importante incorporar estas prácticas de desarrollo.

 

 

🎯 ¿Por qué es IMPORTANTE aplicar CRUD en nuestras aplicaciones?

El CRUD (Crear, Leer, Actualizar, Eliminar) no es solo una técnica de programación, es el núcleo esencial de toda aplicación que maneja datos. Implementarlo correctamente transforma tu código de “algo que funciona” a “algo profesional, mantenible y escalable”.


✅ Beneficios clave de implementar CRUD:

🔧 Simplificación y Estandarización

Ofrece un modelo universal (C, R, U, D) que facilita el desarrollo, colaboración e integración entre sistemas. ¡Todo programador entiende CRUD!

⚡ Eficiencia y Productividad

Te concentras en la lógica de negocio mientras las operaciones básicas de datos son consistentes y predecibles.

🛡️ Gestión Robusta de Datos

Asegura manipulación correcta y eficiente, manteniendo la integridad y consistencia de tu base de datos.

📈 Escalabilidad

Facilita el crecimiento de tu aplicación manteniendo el manejo de datos eficiente aunque aumente el volumen.

😊 Mejora la Experiencia de Usuario

Permite crear, ver, modificar y eliminar datos fácilmente, haciendo tu aplicación intuitiva y amigable.

🤖 Automatización

Elimina la manipulación manual de datos, reduce errores y permite programar operaciones repetitivas.


🎯 En resumen:

Aplicar CRUD es fundamental porque define las operaciones básicas necesarias para cualquier aplicación que maneje datos, desde un simple gestor de contactos hasta complejos sistemas empresariales. Lo hace más fácil de:

  • Construir – Con una estructura clara y organizada
  • Mantener – Con código predecible y fácil de debuggear
  • Escalar – Preparado para crecer sin romperse
  • Entender – Tanto para ti como para otros desarrolladores

💡 Consejo profesional: Aprender CRUD en Python/Flask con JSON te da las bases para trabajar con cualquier tecnología de bases de datos en el futuro.

 

🔥 CHECKLIST PARTE 3 - Lo que vamos a hacer HOY:

⚙️ IMPLEMENTACIÓN CRUD COMPLETA:

  • ✅ Crear método CREATEcrear_contacto() para añadir personas a la base de datos JSON
  • ✅ Sistema de ID auto-incremental persistente que sobreviva a reinicios de la app
  • ✅ Crear método UPDATEactualizar_contacto() para modificar datos existentes
  • ✅ Crear método READleer_contacto() para buscar y listar contactos
  • ✅ Crear método DELETEeliminar_contacto() para borrar registros

🔧 OPTIMIZACIÓN DE CÓDIGO:

  • ✅ Crear funciones auxiliares leer_json() y modificar_json()
  • ✅ Eliminar código repetitivo de apertura/cierre de archivos
  • ✅ Simplificar la estructura del modelo para mayor claridad
  • ✅ Preparar modelo para la conexión con controlador (Parte 4)

🎯 Resultado final: ¡Tendremos un modelo Persona con CRUD completo funcionando y optimizado!

En este post:

  1. Aprenderás el concepto de gestión de datos CRUD.
  2. Vamos a crear los métodos para crear, leer, actualizar y borrar los contactos de nuestra base de datos JSON.
  3. Vamos a corroborar su funcionamiento ejecutando los métodos directamente desde el models.py.
  4. Optimizaremos nuestro código para evitar repeticiones.

 

¿Qué es CRUD?

 

Diagrama explicativo CRUD - Create, Read, Update, DeleteYa hemos hablado anteriormente, pero a modo de repaso el concepto CRUD está estrictamente ligado a la gestión de datos y sus siglas hacen referencia en inglés a Create, Read, Update y Delete (Crear, Leer, Actualizar o modificar y Borrar) por lo que abocándonos a lo que nos compete en el post serán los métodos que vamos a definir para interactuar con nuestra base de datos en este caso JSON aunque es mayormente utilizado con bases de datos relacionales como MySQL, pero es conveniente ir aprendiendo a utilizarlo y aplicarlo cada vez que trabajemos con bases de datos.

 

 

Aplicando el concepto CRUD en nuestro modelo

Para aplicar este concepto debemos definir los métodos correspondientes en nuestra clase y cada método trabajará de una forma determinada. Por ejemplo, el método «Crear» corresponderá a crear nuevos datos en la base de datos y en nuestro caso será «Crear una nueva persona» que será almacenada en la base de datos dentro de la lista que es el valor de la clave «Personas«.

Lo primero es la organización de los datos

 

🔑 CLAVE de IDENTIFICACIÓN (ID)
La importancia del id en las bases de datos en nuestras aplicaciones flaskMe gustaría aclarar que «id» no es solo una clave de identificación de un usuario o «persona / contacto» en nuestro caso. Si no también una manera de diferenciar inequívocamente cada «registro / diccionario» que añadimos y no solamente es buena práctica, sino que utilizarla es obligatorio porque se define como un principio básico de la organización de datos, ya sea trabajes con bases de datos relacionales o no relacionales. Una base de datos sin identificadores únicos e irrepetibles de los registros, no es una base de datos, es un jodido desorden, no es información, son datos aislados y atómicos, regados. Si quieres leer un poco sobre esto lo puedes hacer aquí: Bases de datos – Clave primaria

Creando los métodos CRUD de nuestra clase Personas

Vamos a crear los métodos correspondientes en clase «Personas» de nuestro models.py, pero vamos a comentar en bloques para organizar nuestro código y comprender lo que estamos haciendo:

#BLOQUE IMPORT
import os
import json

#BLOQUE APERTURA ARCHIVO JSON
THIS_FOLDER = os.path.dirname(os.path.abspath(__file__))
my_file = os.path.join(THIS_FOLDER + '/DB/' 'base_de_datos.json')

# Funciones auxiliares
def leer_json():
    with open (my_file, "r") as f:
        datos = json.load(f)
        f.close()
        return datos

def modificar_json():
    with open (my_file, "w") as modid:
        json.dump(datos, modid, indent=4)
        modid.close()

#LEEMOS EL ARCHIVO
datos = leer_json()


#CLASE PERSONA
class Persona(object):
    def __init__(self, id, nombre, apellido, apodo, telefono, direccion):
        self.id = id
        self.nombre = nombre
        self.apellido = apellido
        self.apodo = apodo
        self.telefono = telefono
        self.direccion = direccion

    # Método CREATE - Pendiente de implementar
    def crear_contacto():
        pass
    
    # Método READ - Pendiente de implementar
    def leer_contacto():
        pass

    # Método UPDATE - Pendiente de implementar
    def actualizar_contacto():
        pass

    # Método DELETE - Pendiente de implementar
    def eliminar_contacto():
        pass

🔍 Nota: Este código muestra la estructura base con comentarios por bloques. Los métodos tienen pass porque los implementaremos paso a paso.

¿Cómo crear una id auto-incremental en Python sin librerías?

Lo podemos hacer sin usar ninguna librería:

  1. Creamos una variable para usar de contador dentro de la clase.
  2. En el método constructor de la clase retiramos «id» ya que no vamos a necesitar pasar un argumento para el parámetro «id» porque será asignado automáticamente.
  3. Dentro del método constructor asignamos que el atributo «id» será el valor de la variable de la clase mediante «Persona.contador_id» y finalmente sumamos uno a esta variable.
🆔 Id Auto-incremental sin usar librerías en una clase Python:
Código sin usar librerías:

class Persona(object):
    contador_id = 0 # Variable de clase como contador
    
    def __init__(self, nombre, apellido, apodo, telefono, direccion):
        self.id = Persona.contador_id  # Asigna ID actual
        Persona.contador_id +=1  # Incrementa para próximo objeto
        self.nombre = nombre
        self.apellido = apellido
        self.apodo = apodo
        self.telefono = telefono
        self.direccion = direccion

📝 Nota: Por ahora usaré este enfoque básico. En la siguiente sección veremos cómo hacerlo persistente entre reinicios de la aplicación.

Método Create – crear_contacto()

El método Create nos permitirá crear personas o registros de contactos en nuestra aplicación y almacenarlos en nuestra futura base de datos JSON.

# MÉTODO CREATE - Crear nuevo contacto
def crear_contacto(self):
    # 1. Creamos nueva instancia como diccionario usando __dict__
    nueva_persona = Persona(
        self.nombre,
        self.apellido,
        self.apodo,
        self.telefono, 
        self.direccion).__dict__
    
    # 2. Añadimos a la lista de Personas en memoria
    datos['Personas'].append(nueva_persona)
    
    # 3. Guardamos los cambios en el archivo JSON
    with open (my_file, "w") as fr:
        json.dump(datos, fr, indent =4)
        fr.close()

⚠️ Problema identificado: Este método funciona, pero tiene un defecto crítico: si reiniciamos la aplicación, el contador de IDs vuelve a cero y podríamos tener IDs duplicados.

¿Cómo evitar que nuestro id se repita luego de reiniciar la app?

Primero recuerda que debes crear la base de datos en tu proyecto “DB/base_de_datos.json

 

Para solucionar este problema, creamos dentro de la misma base de datos JSON otra clave que contenga el valor de la id actual:

Archivo /DB/base_de_datos.json:

{
    "Personas": [
        {
            "id": 1,
            "nombre": "Mariano",
            "apellido": "Laca",
            "apodo": "Pyromaniac",
            "telefono": "34343434",
            "direccion": "pythones.net"
        }
    ],
    "Configuraciones":[
        {"contador_id_db" : 1}
    ]
}

Y modificamos en nuestro modelo la clase para usar este valor persistente:

class Persona(object):
    # Contador ID leído desde JSON (persistente entre sesiones)
    contador_id = datos["Configuraciones"][0]["contador_id_db"]
    
    def __init__(self, nombre, apellido, apodo, telefono, direccion):
        print("El contador está en: ", Persona.contador_id)
        self.id = Persona.contador_id
        self.nombre = nombre
        self.apellido = apellido
        self.apodo = apodo
        self.telefono = telefono
        self.direccion = direccion

    def crear_contacto(self):    
        # 1. Incrementamos el contador en la base de datos (JSON)
        datos["Configuraciones"][0]["contador_id_db"] += 1
        
        # 2. Guardamos el nuevo contador en el JSON
        with open (my_file, "w") as modid:
            json.dump(datos, modid, indent=4)
            modid.close()
        
        print("El contador está ahora en: ", datos["Configuraciones"][0]["contador_id_db"])
        # 3. Actualizamos contador en memoria
        Persona.contador_id += 1
        
        # 4. Creamos y guardamos la nueva persona
        nueva_persona = Persona(
            self.nombre,
            self.apellido,
            self.apodo,
            self.telefono, 
            self.direccion).__dict__
            
        datos['Personas'].append(nueva_persona)
        
        with open (my_file, "w") as fr:
            json.dump(datos, fr, indent =4)
            fr.close()

Método Update – actualizar_contacto()

El método Update debe permitirnos cambiar o modificar valores dentro de la base de datos JSON:

# MÉTODO UPDATE - Modificar contacto existente
def actualizar_contacto(id, atr, nuevo_valor):
    for persona in datos["Personas"]:
        if persona["id"] == id:
            print ("Encontrado: ", persona)
            
            # Obtenemos el índice
            indice = datos["Personas"].index(persona)
            
            # Modificamos el valor del atributo especificado
            datos["Personas"][indice][atr] = nuevo_valor
            
            print ("Nuevo valor: ", datos["Personas"][indice][atr])
            
            # Guardamos los cambios en el archivo JSON
            with open (my_file, "w") as modificar:
                json.dump(datos, modificar, indent =4)
                modificar.close()

💡 Explicación: Este método busca un contacto por ID, encuentra su posición en la lista, modifica el atributo especificado y guarda los cambios en el JSON.

Método Read – leer_contacto()

El Método leer_contacto() debe devolvernos el diccionario del contacto que buscamos:

# MÉTODO READ - Buscar y listar contactos
def leer_contacto(atr, valor):
    encontradas = {} # Diccionario para resultados
    
    for persona in datos["Personas"]:
        if persona[atr] == valor or valor == 'all':
            # Obtenemos el índice
            indice = datos["Personas"].index(persona)
            # Guardamos en el diccionario
            encontradas[indice] = persona
    
    return encontradas

🔍 Característica especial: Si pasamos 'all' como valor, devuelve todos los contactos. Si pasamos un valor específico (ej: nombre=”Mariano”), devuelve solo las coincidencias.

Método Delete – eliminar_contacto()

El método para eliminar registros:

# MÉTODO DELETE - Eliminar contacto
def eliminar_contacto(id):
    for persona in datos["Personas"]:
        if persona["id"] == id:
            print ("Se va a borrar: ", persona)
            
            # Obtenemos el índice
            indice = datos["Personas"].index(persona)
            
            # Eliminamos usando pop() con el índice
            datos["Personas"].pop(indice)
            
            # Guardamos los cambios en el JSON
            with open (my_file, "w") as eliminar:
                json.dump(datos, eliminar, indent =4)
                eliminar.close()

⚠️ Precaución: Una vez eliminado un contacto, su ID nunca se reutiliza. Esto es buena práctica para mantener la integridad histórica de los datos.

 

Mejorando el código – Funciones de lectura y escritura JSON

Podemos simplificar mucho el código creando funciones auxiliares para evitar repetir el código de apertura/cierre de archivos:

# ================================================
# FUNCIONES AUXILIARES PARA MANEJO DE JSON
# ================================================

# -- Función Leer archivo JSON
def leer_json():
    with open (my_file, "r") as f:
        datos = json.load(f)
        f.close()
        return datos

# -- Función modificar JSON
def modificar_json():
    with open (my_file, "w") as modid:
        json.dump(datos, modid, indent=4)
        modid.close()

# Cargamos los datos iniciales
datos = leer_json()

Nuestro models.py optimizado queda así:

#BLOQUE IMPORT
import os
import json

#BLOQUE APERTURA ARCHIVO JSON
THIS_FOLDER = os.path.dirname(os.path.abspath(__file__))
my_file = os.path.join(THIS_FOLDER + '/DB/' 'base_de_datos.json')

# Funciones auxiliares
def leer_json():
    with open (my_file, "r") as f:
        datos = json.load(f)
        f.close()
        return datos

def modificar_json():
    with open (my_file, "w") as modid:
        json.dump(datos, modid, indent=4)
        modid.close()

datos = leer_json()

# CLASE PERSONA CON CRUD COMPLETO
class Persona(object):
    contador_id = datos["Configuraciones"][0]["contador_id_db"]

    def __init__(self, nombre, apellido, apodo, telefono, direccion):
        print("El contador está en: ", Persona.contador_id)
        self.id = Persona.contador_id
        self.nombre = nombre
        self.apellido = apellido
        self.apodo = apodo
        self.telefono = telefono
        self.direccion = direccion

    # CREATE
    def crear_contacto(self):
        datos["Configuraciones"][0]["contador_id_db"] += 1
        modificar_json()
        print("El contador está ahora en: ", datos["Configuraciones"][0]["contador_id_db"])
        Persona.contador_id += 1
        
        nueva_persona = Persona(
            self.nombre,
            self.apellido,
            self.apodo,
            self.telefono, 
            self.direccion).__dict__
            
        datos['Personas'].append(nueva_persona)
        modificar_json()

    # READ
    def leer_contacto(atr, valor):
        encontradas = {}
        for persona in datos["Personas"]:
            if persona[atr] == valor or valor == 'all':
                indice = datos["Personas"].index(persona)
                encontradas[indice] = persona
        return encontradas

    # UPDATE
    def actualizar_contacto(id, atr, nuevo_valor):
        for persona in datos["Personas"]:
            if persona["id"] == id:
                indice = datos["Personas"].index(persona)
                datos["Personas"][indice][atr] = nuevo_valor
                modificar_json()

    # DELETE
    def eliminar_contacto(id):
        for persona in datos["Personas"]:
            if persona["id"] == id:
                indice = datos["Personas"].index(persona)
                datos["Personas"].pop(indice)
                modificar_json()

Mucho mejor! ¿No?. ¿Se te ocurre otra forma de organizar y reducir aún más el código?.

 

 

 

Hey!

Esto ha sido todo, nos vemos en la siguiente entrada para conectar el modelo al controlador y finalmente realizar las vistas!. Venga que ya falta poco para terminar nuestra primer aplicación.

 

 

 


📚 NAVEGACIÓN DEL MÓDULO 3

← POST ANTERIOR

 

🗄️ FLASK CON JSON – TUTORIAL 2
Lección 3-7

 

POST SIGUIENTE →

 

🎨 FLASK CON JINJA2 – TUTORIAL 4
Próxima Lección

 

¡Compartir es una forma de agradecer! :)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio