Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
BASE DATOS PYTHON TKINTER
#1
Bug 
Saludos. Alguien puede corregir el código de tal manera que luego de eliminar un registro éste cambio sea permanente??? Luego de eliminar y abrir la BD el registro reaparece.
No hay manera de lograrlo. ME dicen que por el ID pero modifico para que lo muestre y me desajusta lo demás como guardar un nuevo registro.

import tkinter as tk
from tkinter import ttk, messagebox
import sqlite3
import re
from datetime import datetime, timedelta
def conectar_db():
    conexion = sqlite3.connect('mi_base_de_datos3.db')
    cursor = conexion.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS registros (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            REG INT,
            GBT INT,
            CMF INT,
            HOGAR TEXT,
            CPAT_DPAT TEXT,
            CI TEXT,
            NOMBRE TEXT,
            APELLIDO1 TEXT,
            APELLIDO2 TEXT,
            EDAD INTEGER,
            CALLE TEXT,
            No_KM TEXT,
            BARRIO_O_REPARTO TEXT,
            USD TEXT,
            FUM_FUSD DATE,
            FPP DATE,
            SEM INTEGER,
            DIAS INTEGER,
            EG TEXT,
            Trim TEXT,
            CLASIF TEXT,
            FACTORES_DE_RIESGO TEXT,
            OBSERVACIONES TEXT
        )
    ''')
    conexion.commit()
    conexion.close()
def calcular_edad(fecha_nacimiento):
    fecha_actual = datetime.now()
    edad = fecha_actual.year - fecha_nacimiento.year - ((fecha_actual.month, fecha_actual.day) < (fecha_nacimiento.month, fecha_nacimiento.day))
    return edad
class Aplicacion:
    def __init__(self, root):
        self.root = root
        self.root.title("Gestión de Base de Datos")
        self.root.state('zoomed')
        conectar_db()
       
        # Configuración de estilos para el Treeview
        style = ttk.Style(root)
        style.configure("RET.Treeview", background="light blue", foreground="black")
        style.configure("PRO.Treeview", background="light blue", foreground="black")
        style.configure("HOS.Treeview", background="yellow", foreground="black")
        style.configure("NEC.Treeview", background="light green", foreground="black")
        style.configure("PRE.Treeview", background="light grey", foreground="black")
       
        self.campos = ['REG', 'GBT', 'CMF', 'HOGAR', 'CPAT_DPAT', 'CI', 'NOMBRE', 'APELLIDO1', 'APELLIDO2', 'EDAD', 'CALLE', 'No_KM', 'BARRIO_O_REPARTO', 'USD', 'FUM_FUSD', 'FPP', 'SEM', 'DIAS', 'EG', 'Trim', 'CLASIF', 'FACTORES_DE_RIESGO', 'OBSERVACIONES']
        self.entries = {}
        frame_inputs = tk.Frame(root)
        frame_inputs.grid(row=0, column=0, sticky="nsew")
       
        for i, campo in enumerate(self.campos):
            label = tk.Label(frame_inputs, text=campo)
            entry = tk.Entry(frame_inputs, width=17, justify=tk.CENTER)  # Ajusta el ancho según sea necesario
            if i < len(self.campos) / 2:  # Posicionar en la primera fila
                label.grid(column=i, row=0, padx=5, pady=5)
                entry.grid(column=i, row=1, padx=5, pady=5)
            else:  # Posicionar en la segunda fila
                label.grid(column=i - len(self.campos) // 2, row=2, padx=5, pady=5)
                entry.grid(column=i - len(self.campos) // 2, row=3, padx=5, pady=5)
            self.entries[campo] = entry
       
       # Crear el Label para el Entry de filtrado por CMF
        label_filtrar_cmf = tk.Label(frame_inputs, text="Filtrar CMF", font=('Arial', 8, 'bold'))
        label_filtrar_cmf.grid(row=3, column=0, padx=5, pady=5, sticky='w')
       
        # Crear el Entry para filtrar por CMF
        self.entry_filtrar_cmf = tk.Entry(frame_inputs, width=5)
        self.entry_filtrar_cmf.grid(row=4, column=0, padx=5, pady=5)
        self.entry_filtrar_cmf.bind("<KeyRelease>", self.filtrar_por_cmf)
         
        self.boton_ordenar_hogar = tk.Button(frame_inputs, text="Ordenar por HOGAR", command=self.ordenar_por_hogar)
        self.boton_ordenar_hogar.grid(row=len(self.campos) + 1, column=2, pady=10)
       
        self.boton_ordenar_gbt = tk.Button(frame_inputs, text="Ordenar por GBT", command=self.ordenar_por_gbt)
        self.boton_ordenar_gbt.grid(row=len(self.campos) + 1, column=3, pady=10)
       
        self.boton_ordenar_cmf = tk.Button(frame_inputs, text="Ordenar por CMF", command=self.ordenar_por_cmf)
        self.boton_ordenar_cmf.grid(row=len(self.campos) + 1, column=4, pady=10)
       
        self.boton_agregar = tk.Button(frame_inputs, text="Agregar Registro", command=self.agregar_registro)
        self.boton_visualizar = tk.Button(frame_inputs, text="Visualizar Registros", command=self.visualizar_registros)
        self.boton_eliminar = tk.Button(frame_inputs, text="Eliminar Registro", command=self.eliminar_registro)
       
        self.boton_agregar.grid(row=len(self.campos)+1, column=0, pady=10)
        self.boton_visualizar.grid(row=len(self.campos)+1, column=11, pady=10)
        self.boton_eliminar.grid(row=len(self.campos)+1, column=1, pady=10)
    #....................................................................................    
       
        frame_table = tk.Frame(root)
        frame_table.grid(row=1, column=0, sticky="nsew")
        self.tabla = ttk.Treeview(frame_table, columns=self.campos, show="headings")
        for campo in self.campos:
            self.tabla.heading(campo, text=campo)
            self.tabla.column(campo, width=60, minwidth=50)
        self.tabla.grid(row=0, column=0, sticky="nsew")
        frame_table.grid_rowconfigure(0, weight=1)
        frame_table.grid_columnconfigure(0, weight=1)
        root.rowconfigure(1, weight=1)
    #....................................................................................  
       
        self.entries['CI'].bind("<KeyRelease>", self.calcular_edad_evento)
        self.entries['CI'].bind("<FocusOut>", self.validar_ci_evento)
        self.entries['FUM_FUSD'].bind("<FocusOut>", self.validar_fecha_fum_fusd)
        self.entries['FUM_FUSD'].bind("<KeyRelease>", self.actualizar_datos_gestacionales)
        self.entries['DIAS'].bind("<KeyRelease>", self.validar_dias)
        self.entries['SEM'].bind("<KeyRelease>", self.actualizar_datos_gestacionales)
       
        self.visualizar_registros()
        self.ordenar_por_cmf()
       
    #....................................................................................
    def agregar_registro(self):
        if not self.validar_campos() or not self.validar_factores_de_riesgo():
            return
        self.actualizar_datos_gestacionales()  # Asegurarse de que FPP, EG y Trim estén actualizados
        valores = {campo: self.entries[campo].get() for campo in self.entries}
        with sqlite3.connect('mi_base_de_datos3.db') as conexion:
            cursor = conexion.cursor()
            campos = ', '.join(valores.keys())
            placeholders = ', '.join(['?']*len(valores))
            sql = f'INSERT INTO registros ({campos}) VALUES ({placeholders})'
            cursor.execute(sql, list(valores.values()))
            conexion.commit()
        self.visualizar_registros()
    #....................................................................................
   
    def eliminar_registro(self):
        selected_item = self.tabla.selection()
        if not selected_item:
            messagebox.showinfo("Error", "No hay ningún registro seleccionado")
            return
        id = self.tabla.item(selected_item[0])['values'][0]
        try:
            with sqlite3.connect('mi_base_de_datos3.db') as conexion:
                cursor = conexion.cursor()
                cursor.execute('DELETE FROM registros WHERE ID=?', (id,))
                conexion.commit()
            self.tabla.delete(selected_item[0])
        except Exception as e:
            messagebox.showerror("Error", f"No se pudo eliminar el registro: {str(e)}")
   
    #....................................................................................
   
    def filtrar_por_cmf(self, event=None):
        valor_filtro = self.entry_filtrar_cmf.get().strip()
        if valor_filtro:
            try:
                valor_filtro = int(valor_filtro)
                # Obtener los registros filtrados por CMF
                with sqlite3.connect('mi_base_de_datos3.db') as conexion:
                    cursor = conexion.cursor()
                    cursor.execute("SELECT * FROM registros WHERE CMF=?", (valor_filtro,))
                    rows = cursor.fetchall()
                    self.actualizar_vista_treeview(rows)
            except ValueError:
                messagebox.showerror("Error", "El valor para filtrar por CMF debe ser un número entero")
        else:
            # Si el Entry está vacío, mostrar todos los registros
            self.visualizar_registros()
   
    #....................................................................................
   
    def ordenar_por_hogar(self):
        # Obtener los datos y ordenarlos
        with sqlite3.connect('mi_base_de_datos3.db') as conexion:
            cursor = conexion.cursor()
            cursor.execute("SELECT * FROM registros ORDER BY HOGAR")
            rows = cursor.fetchall()
            self.actualizar_vista_treeview(rows)
    #....................................................................................
    def ordenar_por_gbt(self):
        # Obtener los datos y ordenarlos
        with sqlite3.connect('mi_base_de_datos3.db') as conexion:
            cursor = conexion.cursor()
            cursor.execute("SELECT * FROM registros ORDER BY GBT")
            rows = cursor.fetchall()
            self.actualizar_vista_treeview(rows)
    #....................................................................................
    def ordenar_por_cmf(self):
        # Obtener los datos y ordenarlos
        with sqlite3.connect('mi_base_de_datos3.db') as conexion:
            cursor = conexion.cursor()
            cursor.execute("SELECT * FROM registros ORDER BY CMF")
            rows = cursor.fetchall()
            self.actualizar_vista_treeview(rows)
   
    #....................................................................................
   
    def actualizar_vista_treeview(self, rows):
        # Limpiar el Treeview antes de rellenarlo
        for i in self.tabla.get_children():
            self.tabla.delete(i)
        # Insertar los nuevos datos ordenados
        for row in rows:
            estilo = ''
            if row[4] == 'RET':  # Suponiendo que 'HOGAR' es el quinto elemento en la fila
                estilo = 'RET.Treeview'
            elif row[4] == 'PRO':
                estilo = 'PRO.Treeview'
            elif row[4] == 'HOS':
                estilo = 'HOS.Treeview'
            elif row[4] == 'NEC':
                estilo = 'NEC.Treeview'
            elif row[4] == 'PRE':
                estilo = 'PRE.Treeview'
            self.tabla.insert('', 'end', values=row[1:], tags=estilo)
            if estilo:
                self.tabla.tag_configure(estilo, background=('light blue' if row[4] == 'RET' else
                                              'yellow' if row[4] == 'HOS' else
                                              'light green' if row[4] == 'NEC' else
                                              'light grey' if row[4] == 'PRE' else
                                              'light blue' if row[4] == 'PRO' else
                                              'black'))
   
    #....................................................................................
   
    def actualizar_datos_gestacionales(self, event=None):
        if self.validar_fecha(self.entries['FUM_FUSD'].get().strip()):
            self.actualizar_fpp()
            self.actualizar_eg()
            # New: Calculate and update trimester based on EG
            eg = float(self.entries['EG'].get().strip() or 0)
            self.calcular_trim(eg)
    #....................................................................................
    def actualizar_fpp(self):
        fpp = self.calcular_fpp()
        if fpp:
            self.entries['FPP'].delete(0, tk.END)
            self.entries['FPP'].insert(0, fpp)
    #....................................................................................
    def actualizar_eg(self):
        fecha_fum_fusd = self.entries['FUM_FUSD'].get().strip()
        dias_adicionales = int(self.entries['DIAS'].get().strip() or 0)
        semanas_adicionales = int(self.entries['SEM'].get().strip() or 0) * 7
        if self.validar_fecha(fecha_fum_fusd):
            fecha_fum_fusd = datetime.strptime(fecha_fum_fusd, "%Y-%m-%d")
            total_dias = (datetime.now() - fecha_fum_fusd).days + dias_adicionales + semanas_adicionales
            semanas = total_dias // 7
            dias = total_dias % 7
            self.entries['EG'].delete(0, tk.END)
            self.entries['EG'].insert(0, f"{semanas}.{dias}")
            self.calcular_trim(semanas + dias / 7)  # Update Trim based on the new EG        
    #....................................................................................
   
    def calcular_edad_evento(self, event):
        ci = self.entries['CI'].get().strip()
        if len(ci) >= 6:
            try:
                fecha_nacimiento = datetime.strptime(ci[:6], "%y%m%d")
                edad = calcular_edad(fecha_nacimiento)
                self.entries['EDAD'].delete(0, tk.END)
                self.entries['EDAD'].insert(0, str(edad))
            except ValueError:
                pass
   
    #....................................................................................
    def calcular_fpp(self):
        try:
            fecha_fum_fusd = datetime.strptime(self.entries['FUM_FUSD'].get(), "%Y-%m-%d")
            dias = int(self.entries['DIAS'].get() or 0)
            sem = int(self.entries['SEM'].get() or 0)
            fpp = fecha_fum_fusd + timedelta(days=280 - (dias + sem*7))
            return fpp.strftime("%Y-%m-%d")
        except ValueError:
            return ""
    #....................................................................................
    def calcular_trim(self, eg):
        """Calculates and updates the trimester based on gestational age."""
        if eg <= 12.6:
            trim = 'I'
        elif 13 <= eg <= 22.6:
            trim = 'II'
        elif eg >= 23:
            trim = 'III'
        else:
            trim = ''  # In case of an out-of-range or invalid EG value
        self.entries['Trim'].delete(0, tk.END)
        self.entries['Trim'].insert(0, trim)
    #....................................................................................
   
    def visualizar_registros(self):
        for i in self.tabla.get_children():
            self.tabla.delete(i)
        with sqlite3.connect('mi_base_de_datos3.db') as conexion:
            cursor = conexion.cursor()
            cursor.execute("SELECT * FROM registros")
            rows = cursor.fetchall()
            for row in rows:
                estilo = ''
                if row[4] == 'RET':  # Suponiendo que 'HOGAR' es el quinto elemento en la fila
                    estilo = 'RET.Treeview'
                elif row[4] == 'PRO':
                    estilo = 'PRO.Treeview'
                elif row[4] == 'HOS':
                    estilo = 'HOS.Treeview'
                elif row[4] == 'NEC':
                    estilo = 'NEC.Treeview'
                elif row[4] == 'PRE':
                    estilo = 'PRE.Treeview'
                self.tabla.insert('', 'end', values=row[1:], tags=estilo)
                if estilo:
                    self.tabla.tag_configure(estilo, background=('light blue' if row[4] == 'RET' else
                                              'yellow' if row[4] == 'HOS' else
                                              'light green' if row[4] == 'NEC' else
                                              'light grey' if row[4] == 'PRE' else
                                              'light blue' if row[4] == 'PRO' else
                                              'black'))
                   
    #....................................................................................
    def validar_ci_evento(self, event):
        ci = self.entries['CI'].get().strip()
        if not self.validar_ci(ci):
            messagebox.showerror("Error de Validación", "El campo CI debe tener exactamente 11 dígitos y el penúltimo debe ser impar")
            self.entries['CI'].delete(0, tk.END)
            self.entries['CI'].focus_set()
    #....................................................................................
    def validar_ci(self, ci):
        if len(ci) == 11 and ci.isdigit():
            penultimo_digito = int(ci[-2])
            return penultimo_digito % 2 != 0
        return False
   
    #....................................................................................
    def validar_dias(self, event=None):
        dias = self.entries['DIAS'].get().strip()
        if dias:  # Si hay algún valor, verifica que sea adecuado
            if not dias.isdigit() or not (1 <= int(dias) <= 6):
                messagebox.showerror("Error de Validación", "El campo DIAS debe estar en blanco o ser un número entre 1 y 6")
                self.entries['DIAS'].delete(0, tk.END)  # Borra el contenido incorrecto
                self.entries['DIAS'].focus_set()  # Devuelve el enfoque al campo DIAS
            else:
                # Si el valor es válido, actualizamos datos gestacionales.
                self.actualizar_datos_gestacionales()
        else:
            # También actualizar si el campo se deja en blanco, lo que puede cambiar los cálculos.
            self.actualizar_datos_gestacionales()
   
    #....................................................................................
    def validar_factores_de_riesgo(self):
        clasif = self.entries['CLASIF'].get().strip()
        factores_de_riesgo = self.entries['FACTORES_DE_RIESGO'].get().strip()
        if clasif == 'Normal' and factores_de_riesgo:
            messagebox.showerror("Error de Validación", "Si CLASIF es 'Normal', el campo FACTORES_DE_RIESGO debe estar vacío.")
            self.entries['FACTORES_DE_RIESGO'].focus_set()
            return False
        elif clasif in ['ARO', 'BRO', 'CAV'] and not factores_de_riesgo:
            messagebox.showerror("Error de Validación", "Si CLASIF es 'ARO', 'BRO' o 'CAV', el campo FACTORES_DE_RIESGO no puede estar vacío.")
            self.entries['FACTORES_DE_RIESGO'].focus_set()
            return False
        return True
   
    #....................................................................................
    def validar_fecha_fum_fusd(self, event):
        fecha = self.entries['FUM_FUSD'].get().strip()
        if fecha:
            if not self.validar_fecha(fecha):
                messagebox.showerror("Error", "El campo FUM_FUSD debe tener el formato YYYY-MM-DD")
                self.entries['FUM_FUSD'].delete(0, tk.END)
                self.entries['FUM_FUSD'].focus_set()
    #....................................................................................
    def validar_fecha(self, fecha):
        patron = r'\d{4}-\d{2}-\d{2}'
        return re.match(patron, fecha)
    #....................................................................................
    def validar_clasif(self, clasif):
        permitidos = ['Normal', 'ARO', 'BRO', 'CAV']
        return clasif in permitidos
    #....................................................................................
    def validar_campos(self):
        campos_obligatorios = ['GBT', 'CMF', 'CI', 'NOMBRE', 'APELLIDO1', 'APELLIDO2', 'CALLE', 'No_KM', 'BARRIO_O_REPARTO', 'FUM_FUSD', 'CLASIF']
        for campo in campos_obligatorios:
            if not self.entries[campo].get().strip():
                messagebox.showerror("Error", f"El campo {campo} no puede estar vacío")
                self.entries[campo].focus_set()
                return False
            if campo == 'CLASIF' and not self.validar_clasif(self.entries['CLASIF'].get().strip()):
                messagebox.showerror("Error de Validación", "El campo CLASIF debe ser uno de los siguientes: Normal, ARO, BRO, CAV")
                self.entries['CLASIF'].delete(0, tk.END)
                self.entries['CLASIF'].focus_set()
                return False
        return True                
           
root = tk.Tk()
app = Aplicacion(root)
root.mainloop()
Responder
#2
Buenas ocniel. Hagamos una prueba:

Luego de esta línea "id = self.tabla.item(selected_item[0])['values'][0]", ponele a continuación un "print(id)".

Y en este módulo:

with sqlite3.connect('mi_base_de_datos3.db') as conexion:
cursor = conexion.cursor()
cursor.execute('DELETE FROM registros WHERE ID=?', (id,))
conexion.commit()
agregale un mensaje de showinfo "messagebox.showinfo("xx", "xx")"

A ver qué ocurre. Si es que está tomando valor de id (en la primer prueba), y si está ejecutando (debería hacerlo) el delete en el segundo caso. Con respecto a esto último, probá modificando la sentencia a 'DELETE * FROM registros WHERE ID=?', (id,).
Luego me cuentas.
Responder
#3
Hola Diego, gracias. Era el ID oculto, ya lo solucioné.

Gracias por todo.



(02-05-2024, 10:42 AM)Diego escribió: Buenas ocniel. Hagamos una prueba:

Luego de esta línea "id = self.tabla.item(selected_item[0])['values'][0]", ponele a continuación un "print(id)".

Y en este módulo:

            with sqlite3.connect('mi_base_de_datos3.db') as conexion:
                cursor = conexion.cursor()
                cursor.execute('DELETE FROM registros WHERE ID=?', (id,))
                conexion.commit()
agregale un mensaje de showinfo "messagebox.showinfo("xx", "xx")"

A ver qué ocurre. Si es que está tomando valor de id (en la primer prueba), y si está ejecutando (debería hacerlo) el delete en el segundo caso. Con respecto a esto último, probá modificando la sentencia a 'DELETE * FROM registros WHERE ID=?', (id,).
Luego me cuentas.
Responder


Salto de foro:


Usuarios navegando en este tema: 2 invitado(s)