Data entered using form made in tkinter are not inserted in the database

1

I have a Python code with Tkinter where the user must enter their email, password and a destination email. Later this data must be recorded in a database sqlite, but I can not record the data ever.

My code is as follows:

#!/usr/bin/python
# -*- coding: utf-8 -*-

from Tkinter import *
from tkMessageBox import *
import sqlite3

ventana = Tk()
ventana.title ("    ------- CONFIGURAR CUENTAS DE CORREO -------")
ventana.geometry ("500x250+500+250")
Label(ventana, text = "Usuario:").pack()
caja1 = Entry(ventana)
caja1.pack()

Label(ventana, text = "Contraseña:").pack()
caja2 = Entry(ventana, show = "*")
caja2.pack()

Label(ventana, text = "CorreoDestino:").pack()
caja3 = Entry(ventana)
caja3.pack()

def login():
    # Connect to database
    db = sqlite3.connect('C:\robots\login.db')
    c = db.cursor()

    c.execute("delete from usuarios where 1")

    usuario = caja1.get()
    contr = caja2.get()
    destino = caja3.get()

    try:
        c.execute("INSERT INTO usuarios (usuario, pass, destino)  values({0},{1},{2});".format(usuario,contr,destino))
        showinfo(title = "Configuracion correcta", message = "DATOS ALMACENADOS CORRECTAMENTE")
        db.commit()
        c.close()

    except:
        showerror(title = "Configuracion incorrecta", message = "DATOS NO ALMACENADOS")
        db.rollback()


    c.close()

Button (text = "Guardar", command = login).pack()

What am I doing wrong?

    
asked by Ricardo Ulises Prado Uribe 28.04.2018 в 06:03
source

1 answer

1

The query to insert the data is incorrect, in addition you should not use Python string formatting to create a query ever, this can lead to your code being susceptible to SQL injection attack. You should do for example:

c.execute("INSERT INTO usuarios (usuario, pass, destino)  VALUES(?, ?, ?);",
          (usuario, contr, destino)
         )

Keep in mind that you do not execute the mainloop of the application at any time (unless code is missing). If so, you probably use the IDLE, which is written in Tkinter and has its own mainloop , but the code will not work outside the IDLE without it.

Always be careful with try-except when handling exceptions, even more in the development phase, the error would be much easier to locate if you at least print it, for example, if you enter "Ricardo" in the user you would get something like this:

Traceback (most recent call last):
  File "main.py", line 34, in login
    c.execute("INSERT INTO usuarios (usuario, pass, destino)  values({0},{1},{2});".format(usuario,contr,destino))
OperationalError: no such column: ricardo

Which already tells you where the error goes quite clearly. The values must be quoted in the query, for example this would work:

'INSERT INTO usuarios (usuario, pass, destino)  values("{0}","{1}","{2}");'.format(usuario, contr, destino)

But again, do not use str.format for this.

I leave the complete code with some modifications in case you want to reproduce:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sqlite3
import Tkinter as tk
import tkMessageBox
import traceback

ventana = tk.Tk()
ventana.title ("    ------- CONFIGURAR CUENTAS DE CORREO -------")
ventana.geometry ("500x250+500+250")

user = tk.StringVar(ventana)
tk.Label(ventana, text = "Usuario:").pack()
caja1 = tk.Entry(ventana, textvariable=user)
caja1.pack()

passw = tk.StringVar(ventana)
tk.Label(ventana, text = "Contraseña:").pack()
caja2 = tk.Entry(ventana, show = "*", textvariable=passw)
caja2.pack()

mail = tk.StringVar(ventana)
tk.Label(ventana, text = "CorreoDestino:").pack()
caja3 = tk.Entry(ventana, textvariable=mail)
caja3.pack()

user.trace("w", lambda *args: caja1.config({"background": "#ffffff"}))
passw.trace("w", lambda *args: caja2.config({"background": "#ffffff"}))
mail.trace("w", lambda *args: caja3.config({"background": "#ffffff"}))


def check_table(conn):
    try:
        cursor = conn.cursor()
        cursor.execute(""" CREATE TABLE IF NOT EXISTS usuarios (
                                        id integer PRIMARY KEY,
                                        usuario text NOT NULL,
                                        pass text NOT NULL,
                                        destino text
                                    ); """
                       )
        cursor.execute("DELETE FROM usuarios WHERE 1")  # ? Borra todas las filas
        conn.commit()  

    except:
        traceback.print_exc()
        return False

    return True


def get_data():
    usuario = user.get()
    contr = passw.get()
    destino = mail.get()

    valid = True
    if not usuario:
        caja1.config({"background": "#ff9999"})
        valid = False
    if not contr:
        caja2.config({"background": "#ff9999"})
        valid = False
    if not destino:
        caja3.config({"background": "#ff9999"})
        valid = False

    if valid:
        return usuario, contr, destino

    return None


def insert_user(conn, data):
    try:
        cursor = conn.cursor()
        cursor.execute('''INSERT INTO usuarios (usuario, pass, destino)
                               VALUES(?, ?, ?);''',
                       data
                      )
        conn.commit()

    except:
        traceback.print_exc()
        return False

    return True


def login():
    path = 'C:\robots\login.db'
    try:
        db = sqlite3.connect(path)
    except:
        traceback.print_exc()
        tkMessageBox.showerror(title="Configuración incorrecta",
                               message="NO HA SIDO POSIBLE CONECTARSE CON LA BD"
                               )
        return 

    if check_table(db):
        data = get_data()
        if data is not None:
            ins = insert_user(db, data)
            if ins:
                tkMessageBox.showinfo(title="Configuración correcta",
                                      message="DATOS ALMACENADOS CORRECTAMENTE"
                                     )
            else:
                tkMessageBox.showinfo(title="Configuración incorrecta",
                                      message="LOS DATOS NO HAN PODIDO SER ALMACENADOS"
                                     )
        else:
            tkMessageBox.showerror(title="Entrada inválida",
                                   message="TODOS LOS CAMPOS SON OBLIGATORIOS"
                                  )
    else:
        tkMessageBox.showerror(title="Configuración incorrecta",
                               message="NO HA SIDO POSIBLE ACCEDER NI CREAR LA TABLA 'usuarios'"
                              )

    db.rollback()
    db.close()

tk.Button (text = "Guardar", command = login).pack()
ventana.mainloop()

The most important changes are:

  • Exceptions other than producing a messagebox for the user are printed as is in the terminal, which will help you detect possible errors while developing.

  • The imports of the form from modulo import * have been removed, as a rule this is a bad practice.

  • The get_data function validates that the entry is correct before attempting to insert the data. In this case only check that the boxes are not empty, showing an error message and shading in red the entry that is. You could use it to validate the data itself, for example, that the email has a valid format.

  • The function check_table verifies that the table exists, if it does not exist, it tries to create it. This I have done more than anything so that the code is easily reproducible for others. If you leave it like this, check and modify the structure of the table properly.

The code can be structured in other ways, it would be preferable to use POO but this already requires moving too far from the original code.

    
answered by 28.04.2018 / 14:56
source