jueves, 11 de septiembre de 2008

Lección No. 5

Antes que nada... perdón por la demora.

Con la lección de hoy aprenderemos cómo conectarnos a MySQL desde python y cómo hacer algunas acciones básicas de las bases de datos: guardar, buscar, eliminar, actualizar. Todo ello utilizando Python MySQL y VisualWx.


Material de trabajo para esta lección
Para la lección de hoy vamos a necesitar instalar un servidor de MySQL, para ello puedes descargar el AppServ para windows que además te instala el Apache y el Php (claro que eso no los necesitamos pero.... pues matas varios pájaros de un solo tiro), lo puedes encontrar en http://www.appservnetwork.com/index.php?newlang=spanish actualmente yo utilizo la versión 2.5.8. porque la descargue hace mucho tiempo y me ha funcionado sin problemas, pero si ves la página notarás que van en la versión 2.6, ten cuidado con la vesión que descargues ya que tiene que ser compatible con la API que ofrece python para MySQL; Descargalo y cuando lo estés instalando asegurate de asignar una clave al MySQL.

También necesitamos el MySQL-python que lo puedes encontrar en http://sourceforge.net/projects/mysql-python/ descargas e instalas sin mayores inconvenientes (siguiente, siguiente...)

Si sabes pocon pocon de bases de datos, te recomendaría que te descargues también el HeidiSQL de http://www.heidisql.com/ que es un GUI gratis que te permitirá crear tablas, editarlas, etc. y hasta aprender algunas cosas de bdd. Actualmentemente va por la versión 3.2


Manos a la obra
Con estas herramientas ya instaladas procederemos con la lección de hoy, que inicialmente será algo sencillo pero que en las próximas lecciones iremos enriqueciendo.

Lo primero es lo primero, para quienes no sepan qué es MySQL (aunque si estás aquí me imagino que alguito debes saber) en resumidas cuentas podemos decir que es un sistema de gestión de bases de datos similar al SQLite, Postgress, Oracle, entre otros cada uno con sus pequeñas diferencias, sus pro y sus contra, puedes encontrar más documentación en san google.

El archivo MySQL-python-1.2.2.win32-py2.5 (o similar) sera el que nos permita hacer el “enlace” o conexión desde Python con la bdd (base de datos).

Vamos a crear nuestra base de datos y luego la utilizaremos desde VisualWx; si bajaste el HeidiSQL, lo abres, configuras la conexión con la base de datos MySQL (con la clave que le has puesto al instalar el AppServ).


Ya dentro del programa vamos a crear una base de datos denominada afiliados. Para crearla desde el HeidiSQL solo basta con hacer clic derecho en root@localhost seleccionar create database.... y seguir las instrucciones:


Ahora crearemos la tabla para la base de datos afiliados. Lo podemos hacer de varias formas, explicare solo dos, desde HeidiSQL y desde consola:

HeidiSQL
Teniendo seleccionada la base de datos afiliados da clic en el menú tools y de este menú selecciona Create Table, luego ingresa los diferentes campos con sus propiedades, algo como esto:

No olvides cambiar el tipo de dato y su longitud. Por último clic en el botón Create!

Si no te has descargado el Heidi, entonces desde consola se hace así:
Clic en Inicio – Ejecutar – cmd y Enter

Estando en el prompt de win2 digitas: mysql -u root -p y presionas enter.
Se te pedirá la clave que es la que digitaste cuando estabas instalando el AppServ.

Una vez ingreses digitas lo siguiente:

mysql>use afiliados;

Lo anterior es para usar la base de datos afiliados. Ahora a crear la tabla. Digita:

CREATE TABLE personas(
doc INT (11) UNSIGNED NOT NULL, nombre1 VARCHAR (12) NOT NULL,
nombre2 VARCHAR (12), apellido1 VARCHAR (12) NOT NULL,
apellido2 VARCHAR (12), direccion VARCHAR (35) NOT NULL,
telefono VARCHAR (11));

Ya tenemos nuestra base de datos creada (afiliados) con una tabla definida (personas).

Como este no es un tutorial de MySQL deberás buscar en san google si quiere aprender más sobre este sistema de bases de datos.

Ahora abrimos nuestro VisualWx y creamos una nueva aplicación WX_SDI_PYTHON, la guardas en una carpeta con el nombre que quieras (yo le he puesto afiliaciones -que imaginación la mía-).

Le cambiamos el color al form, el tamaño de la fuente; en la propiedad Title: Control de afiliados con MySQL o lo que quieras colocar.

NOTA
Debido a un lapsus mental se me ha ido el título de la ventana "Control de afiliados con SQLite", pero en realidad debería decir "Control de afiliados con MySQL".

Ahora vamos a ubicar los controles para obtener algo como esto:


Esta es la lista de los controles con sus nombres:

Antes de programar conectándonos a la bdd sería bueno programar los focos de los controles. Para iniciar podemos seleccionar el txt_doc y el ficha propiedades cambiar Focus a true, eso hará que cuando se active el form, el foco inicie en este control.

Ahora haremos que cuando se presione cualquiera de las teclas enter/intro o la tecla tab, se cambie el foco al siguiente control.

Mi primer control (documento) se denomina txt_doc y le sigue txt_nombre1, para programar esta acción estando ubicado el txt_doc hago clic en la ficha events y busco el EVT_KEY_DOWN, le doy el nombre a la función y luego en la ficha Python que se encuentra debajo del Form busco la función (yo le he puesto va_n1) y digito lo siguiente:

def va_n1(self,event): #init function
#add your code here
key = event.GetKeyCode()

if key==9 or key==13 or key==wx.WXK_NUMPAD_ENTER:
self.txt_nombre1.SetFocus()

event.Skip()

return #end function

Lo misma forma debes proceder con cada uno de los controles teniendo en cuenta a qué control debe llegar el foco.
Ejecuta el programa (F5) y verifica que todos los focus estén funcionando correctamente.

Si todo anda bien, entonces procedamos con la programación de la base de datos (bdd) y los botones.

Para conectarnos a la base de datos en la parte superior de nuestro código vamos a digitar lo siguiente:

import MySQLdb as con
db = con.connect(host='localhost', user='root', passwd='tuclave', db='afiliados')
c = db.cursor()

Esto importa el MySQL al que denominamos con y luego nos permite hacer la conexión con nuestra bdd denominada afiliados.



Ahora vamos a programar el botón guardar.

Clic en el botón guardar.
Clic en la ficha events.
Clic en el botón E (Component Events)
Clic en el EVT_BUTTON
Dale el nombre a la función, yo le he puesto guarda_datos (sigo impresionado con mi imaginación para asignar nombres!!!)

Vamos a la ficha Python (si la del centro) y buscamos la función que acabamos de crear; allí escribimos lo siguiente:

def guarda_datos(self,event): #init function
#add your code here
doc = self.txt_doc.GetValue()
n1 = self.txt_nombre1.GetValue()
n2 = self.txt_nombre2.GetValue()
ap1 = self.txt_apellido1.GetValue()
ap2 = self.txt_apellido2.GetValue()
di = self.txt_direccion.GetValue()
te = self.txt_telefono.GetValue()

"""Vamos a poner una pequeña restricción que obligue
al usuario a escribir por lo menos el doc, el nombre1
apellido1 y la direccion"""

if doc<>'' and n1<>'' and ap1<>'' and di<>'':
sql = c.execute('INSERT INTO personas VALUES(%s,%s,%s,%s,%s,%s,%s)',
(doc,n1,n2,ap1,ap2,di,te))
res = c.fetchall()

if res<>None:
w=wx.MessageDialog(self,u"Registro almacenado con éxito","REGISTRO",wx.OK | wx.ICON_INFORMATION)
w.ShowModal()
w.Centre()
w.Destroy

self.txt_nombre1.SetLabel('')
self.txt_nombre2.SetLabel('')
self.txt_apellido1.SetLabel('')
self.txt_apellido2.SetLabel('')
self.txt_direccion.SetLabel('')
self.txt_telefono.SetLabel('')

self.txt_doc.SetFocus()
else:
w = wx.MessageDialog(self,u"Faltan datos por ingresar","ERROR DE DATOS",wx.OK | wx.ICON_EXCLAMATION)
w.ShowModal()
w.Centre()
w.Destroy

self.txt_doc.SetFocus()

return #end function

No olvide los tabulados (identaciones) por favor....

Probamos ejecutando el programa e ingresando cualquier dato para guardarlo utilizando el botón, puede ser nuestro nombre:


El siguiente código puede ser utilizado para diferentes cosas, principalmente para evitar registros duplicados o para localizar rapidamente la información.

Selecciona el txt_doc y en la ficha events localiza el EVT_KILL_FOCUS asignale un nombre a la función, yo le he puesto consulta_datos. Esta función hace que una vez el control txt_doc pierda el foco se active el código de dicha función. Si lo prefieres puedes no utilizar este evento sino el de EVT_SET_FOCUS del control txt_nombre1 el cual recibe el foco después del txt_doc.

Si ya definiste el nombre de la función vamos a copiar el siguiente código:

def consulta_datos(self,event): #init function
#add your code here
doc = self.txt_doc.GetValue()

sql = c.execute('SELECT * FROM personas WHERE doc=%s',(doc))
res = c.fetchall()

if res<>None:
for i in res:
self.txt_nombre1.SetLabel(str(i[1]))
self.txt_nombre2.SetLabel(str(i[2]))
self.txt_apellido1.SetLabel(str(i[3]))
self.txt_apellido2.SetLabel(str(i[4]))
self.txt_direccion.SetLabel(str(i[5]))
self.txt_telefono.SetLabel(str(i[6]))

event.Skip()

return #end function

A grandes rasgos:

doc = self.txt_doc.GetValue() toma el valor del control y lo almacena en la variable doc.

sql = c.execute('SELECT * FROM personas WHERE doc=%s',(doc))
Genera la consulta sql reemplanzando %s por el contenido de la variable doc

res = c.fetchall()
El resultado de la consulta (número de filas devueltas)

if res<>None:
Si el resultado es diferente de vacío.

for i in res:
Se toma la variable i hasta res y se ....

self.txt_nombre1.SetLabel(str(i[1]))
... coloca el valor de cada i[X] en el respectivo control.

A veces ni yo mismo me entiendo per sí sé lo que digo!!! Si hay alguien más que pueda explicar de otra forma más clara o sencilla bienvenido sea.

Qué quiere decir todo esto... que si ejecutas el programa y vuelves a escribir un documento de identidad que YA EXISTE en la base de datos éste (la función) recupera/carga inmediatamente los datos en el form. Uff!!


El código para el botón buscar:
Haces clic en el botón buscar, luego vas a la ficha events, botón E, localizas el EVT_BUTTON, le das un nombre a la función, yo le he puesto.... buscar (qué imaginación) y escribes el siguiente código:

doc = self.txt_doc.GetValue()

sql = c.execute('SELECT * FROM personas WHERE doc=%s',(doc))
res = c.fetchall()

if res<>None:
for i in res:
self.txt_nombre1.SetLabel(str(i[1]))
self.txt_nombre2.SetLabel(str(i[2]))
self.txt_apellido1.SetLabel(str(i[3]))
self.txt_apellido2.SetLabel(str(i[4]))
self.txt_direccion.SetLabel(str(i[5]))
self.txt_telefono.SetLabel(str(i[6]))

event.Skip()

El código para el botón actualizar:
Hacemos el procedimiento como en el botón anterior; yo le he puesto actualiza_datos a la función y el código es el siguiente:

def actualiza_datos(self,event): #init function
#add your code here
doc = self.txt_doc.GetValue()
n1 = self.txt_nombre1.GetValue()
n2 = self.txt_nombre2.GetValue()
ap1 = self.txt_apellido1.GetValue()
ap2 = self.txt_apellido2.GetValue()
di = self.txt_direccion.GetValue()
te = self.txt_telefono.GetValue()

"""Se supone en este ejercicio que podemos actualizar
todos los datos menos el doc de identidad, para poder
cambiar el doc de identidad lo ideal sería haber creado
un indice o campo autonumeríco en la tabla personas"""
sql = c.execute('UPDATE personas SET nombre1=%s,nombre2=%s, \
apellido1=%s,apellido2=%s,direccion=%s,telefono=%s \
WHERE doc=%s',(doc,n1,n2,ap1,ap2,di,te,doc))
res = c.fetchall()

w = wx.MessageDialog(self,u"Registro actualizado con éxito",u"ACTUALIZACIÓN",wx.OK | wx.ICON_INFORMATION )
w.ShowModal()
w.Centre()
w.Destroy()

#Preparamos el form para más datos
self.txt_doc.SetLabel('')
self.txt_nombre1.SetLabel('')
self.txt_nombre2.SetLabel('')
self.txt_apellido1.SetLabel('')
self.txt_apellido2.SetLabel('')
self.txt_direccion.SetLabel('')
self.txt_telefono.SetLabel('')

self.txt_doc.SetFocus()

return #end function


El código para el botón eliminar:
def elimina_datos(self,event): #init function
#add your code here
doc = self.txt_doc.GetValue()

sql = c.execute('DELETE FROM personas WHERE doc=%s',(doc))
res = c.fetchall()

w = wx.MessageDialog(self,u"Registro eliminado con éxito","REGISTRO",wx.OK | wx.ICON_EXCLAMATION)
w.ShowModal()
w.Centre()
w.Destroy()

self.txt_nombre1.SetLabel('')
self.txt_nombre2.SetLabel('')
self.txt_apellido1.SetLabel('')
self.txt_apellido2.SetLabel('')
self.txt_direccion.SetLabel('')
self.txt_telefono.SetLabel('')

self.txt_doc.SetFocus()

return #end function

Y el código para el botón cerrar:
self.Close()

Obviamente estos códigos son algo “simples” ya que se debería programar teniendo en cuenta algunas restricciones o situaciones en ciertos momentos como lo es por ejemplo al momento de eliminar datos, sin embargo estos pequeños código servirán como ilustración para hacer otras cosas de mayor importancia.

Eso es todo por ahora.