jueves, 25 de junio de 2009

Crear una [pequeña] aplicación completa usando wxPython (Parte 3)

.
10 comentarios

En esta oportunidad crearemos el Controlador de la Vista Principal, y por primera vez podremos ejecutar nuestra aplicación. Sin mas preámbulo, empecemos!.

Codificando el Controlador de la Vista Principal

Para comenzar, voy a citar el punto 2 del artículo de la Wikipedia que les comentaba en la parte anterior del tutorial.

"… 1. El controlador recibe (por parte de los objetos de la interfaz-vista) la notificación de la acción solicitada por el usuario. El controlador gestiona el evento que llega, frecuentemente a través de un gestor de eventos (handler) o callback. ..."

Este punto nos esta diciendo:

1. El Controlador recibe desde la Vista, la notificación de la acción solicitada por el usuario (ej: "se pulso el botón Salir", "se pulso el botón Agregar Película", etc.).

2. El Controlador gestiona el evento, haciendo una llamada a quien corresponda para que atienda esa acción en particular (ej: "Si el usuario pulso el botón Agregar Película llamar al método onAgregarPelicula, para que se encargue de mostrar el Editor de Películas").

Teniendo estos dos puntos presentes, nuestro Controlador para la Vista Principal, podría (inicialmente) ser algo así:

controladorVistaPrincipal.py
import wx

from wx import xrc

from vistas.vistaPrincipal import VistaPrincipal

class ControladorVistaPrincipal:
def __init__(self, app):
self.app = app

self.vista = VistaPrincipal(app)

#Items del Menú
self.vista.frame.Bind(wx.EVT_MENU, self.onMostrarAgregarPelicula, id=xrc.XRCID('itemAgregarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onMostrarEditorDePelicula, id=xrc.XRCID('itemEditarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onEliminarPelicula, id=xrc.XRCID('itemEliminarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onSalir, id=xrc.XRCID('itemSalir'))

#Botones de la barra de herramientas
self.vista.frame.Bind(wx.EVT_TOOL, self.onMostrarAgregarPelicula, id=xrc.XRCID('toolAgregarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onMostrarEditorDePelicula, id=xrc.XRCID('toolEditarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onEliminarPelicula, id=xrc.XRCID('toolEliminarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onBuscarPelicula, id=xrc.XRCID('toolBuscarPelicula'))

def onMostrarAgregarPelicula(self, evt):
...

def onMostrarEditorDePelicula(self, evt):
...

def onEliminarPelicula(self, evt):
...

def onBuscarPelicula(self, evt):
...

def onSalir(self, evt):
self.app.Exit()

Lo primero que hacemos en esta clase es crear la Vista Principal de la aplicación (aunque aún no la mostramos).

self.vista = VistaPrincipal(app)

después "enlazamos" los eventos que nos interesan con su correspondiente manejador de evento. Primero lo hacemos para cuando sean activados los items del menú

#Items del Menú
self.vista.frame.Bind(wx.EVT_MENU, self.onMostrarAgregarPelicula, id=xrc.XRCID('itemAgregarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onMostrarEditorDePelicula, id=xrc.XRCID('itemEditarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onEliminarPelicula, id=xrc.XRCID('itemEliminarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onSalir, id=xrc.XRCID('itemSalir'))

y luego para cuando sean pulsados los botones de la barra de herramientas

#Botones de la barra de herramientas
self.vista.frame.Bind(wx.EVT_TOOL, self.onMostrarAgregarPelicula, id=xrc.XRCID('toolAgregarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onMostrarEditorDePelicula, id=xrc.XRCID('toolEditarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onEliminarPelicula, id=xrc.XRCID('toolEliminarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onBuscarPelicula, id=xrc.XRCID('toolBuscarPelicula'))

Pueden observar que algunos manejadores de eventos son llamados como respuesta a mas de un evento, por ej: tanto el ítem del menú "Eliminar" como el botón "Eliminar" de la barra de herramientas, están asociados al manejador de eventos onEliminarPelicula.

Como ultimo paso, creamos (a medias) los distintos manejadores de eventos que serán llamados según las acciones que solicite el usuario.

def onMostrarAgregarPelicula(self, evt):
...

def onMostrarEditorDePelicula(self, evt):
...

def onEliminarPelicula(self, evt):
...

def onBuscarPelicula(self, evt):
...

def onSalir(self, evt):
self.app.Exit()

Ahora haremos referencia al punto 2 del artículo de la Wikipedia, para seguir creando nuestro Controlador

"... 2. El controlador accede al modelo, actualizándolo, posiblemente modificándolo de forma adecuada a la acción solicitada por el usuario (por ejemplo, el controlador actualiza el carro de la compra del usuario). Los controladores complejos están a menudo estructurados usando un patrón de comando que encapsula las acciones y simplifica su extensión. ..."

Leyendo este punto, vemos que nuestro Controlador se encarga de acceder al Modelo y hacer las modificaciones necesarias. En nuestro caso la tarea de agregar y eliminar una película no estará a cargo de este Controlador sino a cargo del Controlador de la Vista del Editor de Películas, pero en el caso de que se quiera eliminar una película, esta acción si será llevada a cabo por el método onEliminarPelicula de este Controlador, y sería mas o menos así:

def onEliminarPelicula(self, evt):
id_pelicula = self.vista.getIDItemSeleccionado()

self.app.modelo.eliminarPelicula(id_pelicula)

así de simple es la tarea de eliminar la película que este seleccionada en el listado de la Vista Principal. Primero obtenemos el ID de la película seleccionada con el método getIDItemSeleccionado de la Vista Principal y luego llamamos al método onEliminarPelicula del Modelo pasándole el ID de la película que deseamos borrar, pero por si no lo recuerdan, el método getIDItemSeleccionado aún no lo hemos creado, así que debemos agregar el siguiente código a la clase VistaPrincipal:

def getIDItemSeleccionado(self):
itemIndex = self.listaDePeliculas.GetFirstSelected()
return self.listaDePeliculas.GetItemData(itemIndex)

en este método obtenemos un referencia al ítem seleccionado y luego retornamos el ID que esta asociado a éste.

Por ahora no nos estamos preocupando por las validaciones, pero mas adelante volveremos sobre esto. También deberíamos pedir una confirmación antes de borrar la película, e incluso podríamos dar la posibilidad de borrar de a mas de una película al mismo tiempo, pero por el momento quedará pendiente.

Los métodos onMostrarAgregarPelicula y onMostrarEditorDePelicula serán (justamente) los encargados de mostrar el Editor de Películas en modo Agregar o Modificar respectivamente. Como aún no tenemos ni la Vista ni el Controlador del Editor de Películas, por ahora haremos que sólo se muestre un mensaje diciendo qué debería suceder al ser llamados, es decir que quedarían así:

def onMostrarAgregarPelicula(self, evt):
wx.MessageBox("Mostrar el Editor de Películas para agregar una película")

def onMostrarEditorDePelicula(self, evt):
wx.MessageBox("Mostrar el Editor de Películas para modificar la película seleccionada")

También hacemos lo mismo con el método onBuscarPelicula:

def onBuscarPelicula(self, evt):
wx.MessageBox("Buscar una película")

En este punto nos referiremos a una parte del punto 4 del artículo que hemos tomado como referencia:

"... 4. … El controlador no pasa objetos de dominio (el modelo) a la vista aunque puede dar la orden a la vista para que se actualice. Nota: En algunas implementaciones la vista no tiene acceso directo al modelo, dejando que el controlador envíe los datos del modelo a la vista. ..."

De las dos implementaciones que nos habla este punto, nosotros usaremos la primera, es decir que el Controlador no pasará información del Modelo a la Vista, sino que el Controlador sólo avisará cuando haya alguna modificación en el Modelo, y será la Vista la encargada de actualizarse. Teniendo esto claro, necesitamos algún mecanismo para que el Controlador "se entere" de que el Modelo ha cambiado. Si hacemos un poco de memoria, recordaremos que el modelo "avisaba" cuando se agregaba, modificaba o eliminaba una película haciendo uso del modulo wx.lib.pubsub, a través del método sendMessage() del objeto Publisher, o sea que lo único que nos quedaría por hacer es suscribirnos a esos mensajes y así quedarnos a la escucha de estos. Para llevar a cabo esta tarea, simplemente utilizamos el método suscribe() del objeto Publisher de la siguiente manera:

Publisher.subscribe(self.seModificoElModelo, 'pelicula_agregada')
Publisher.subscribe(self.seModificoElModelo, 'pelicula_modificada')
Publisher.subscribe(self.seModificoElModelo, 'pelicula_eliminada')

Con estas tres lineas, lo que estamos haciendo es quedarnos a la escucha de los mensajes 'pelicula_agregada', 'pelicula_modificada' y 'pelicula_eliminada', y de ser recibidos, llamamos (por ahora) al método seModificoElModelo, que codificaremos así:

def seModificoElModelo(self, mensaje):
self.vista.cargarListadoDePeliculas()

Lo único que estamos haciendo aquí, es invocar el método cargarListadoDePeliculas() de la Vista Principal, con lo cual se recargarían las películas y así se vería reflejado el cambio que se ha producido en el Modelo (se agrego, modifico o elimino una película).

Por último, una vez que nos suscribimos a los mensajes que nos interesan, nos queda cargar el listado de películas y hacer visible la Vista:

self.vista.cargarListadoDePeliculas()
self.vista.Mostrar()

A continuación les muestro como queda la clase completa hasta ahora:

import wx

from wx import xrc
from wx.lib.pubsub import Publisher

from vistas.vistaPrincipal import VistaPrincipal

class ControladorVistaPrincipal:
def __init__(self, app):
self.app = app
self.vista = VistaPrincipal(app)

#Items del Menú
self.vista.frame.Bind(wx.EVT_MENU, self.onMostrarAgregarPelicula, id=xrc.XRCID('itemAgregarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onMostrarEditorDePelicula, id=xrc.XRCID('itemEditarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onEliminarPelicula, id=xrc.XRCID('itemEliminarPelicula'))
self.vista.frame.Bind(wx.EVT_MENU, self.onSalir, id=xrc.XRCID('itemSalir'))

#Botones de la barra de herramientas
self.vista.frame.Bind(wx.EVT_TOOL, self.onMostrarAgregarPelicula, id=xrc.XRCID('toolAgregarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onMostrarEditorDePelicula, id=xrc.XRCID('toolEditarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onEliminarPelicula, id=xrc.XRCID('toolEliminarPelicula'))
self.vista.frame.Bind(wx.EVT_TOOL, self.onBuscarPelicula, id=xrc.XRCID('toolBuscarPelicula'))

#Me suscribo a los mensajes que indican que se modifico el Modelo
Publisher.subscribe(self.seModificoElModelo, 'pelicula_agregada')
Publisher.subscribe(self.seModificoElModelo, 'pelicula_modificada')
Publisher.subscribe(self.seModificoElModelo, 'pelicula_eliminada')

#Cargo la lista de peliculas
self.vista.cargarListadoDePeliculas()

self.vista.Mostrar()

def onMostrarAgregarPelicula(self, evt):
wx.MessageBox("Mostrar el Editor de Peliculas para agregar una pelicula")

def onMostrarEditorDePelicula(self, evt):
wx.MessageBox("Mostrar el Editor de Peliculas para modificar la pelicula seleccionada")

def onEliminarPelicula(self, evt):
id_pelicula = self.vista.getIDItemSeleccionado()
self.app.modelo.eliminarPelicula(id_pelicula)

def onBuscarPelicula(self, evt):
wx.MessageBox("Buscar una pelicula")

def onSalir(self, evt):
self.app.Exit()
Con esto tenemos el Modelo, y la Vista y el Controlador de la Ventana Pricipal en condiciones de ser ejecutados, pero aún nos falta crear la clase que representa la aplicación, que será el punto de partida para que nuestro Catálogo puede iniciarse.

Codificando la clase de la Aplicación

Primero les mostrare el código de esta pequeña clase, y luego iremos paso a paso viendo que es lo que hace:

catalogo.py
import wx
from wx import xrc
from controladores.controladorVistaPrincipal import ControladorVistaPrincipal
from modelo import Model

class CatalogoDePeliculas(wx.App):
def OnInit(self):
self.modelo = Model()
self.res = xrc.XmlResource('gui.xrc')

self.controladorVistaPrincipal = ControladorVistaPrincipal(self)

return True

app = CatalogoDePeliculas()
app.MainLoop()

En primer lugar vemos que dentro de los modulos que importamos, se encuentran el Controlador de la Vista Principal (ControladorVistaPrincipal) y el Modelo (Model). También notamos que el nombre de la clase es CatalogoDePeliculas y que esta deriva de wx.App. Ya en el método OnInit, vemos que instanciamos self.modelo con el Modelo de la aplicación:

self.modelo = Model()

luego, cargamos el archivo de recursos

self.res = xrc.XmlResource('gui.xrc')

creamos el Controlador de la Vista Principal, al cual le pasamos la propia aplicación como parámetro

self.controladorVistaPrincipal = ControladorVistaPrincipal(self)

y ya fuera de la clase, creamos la aplicación e iniciamos el bucle principal.

De este modo, estamos listos para poder ver nuestra aplicación en marcha, ejecutando este archivo (catalogo.py). Si bien aún no podemos editar las películas del catálogo, podriamos agregar algunas películas en forma manual dentro de la base de datos, y al ejecutar el catálogo veríamos que estas se cargarían en el listado, e incluso las podríamos eliminar.

Hasta aquí hemos llegado en esta entrega. En la próxima trabajaremos en el Editor de Películas y así seguiremos agregando funcionalidad a nuestro pequeño Catálogo de películas.

Saludos!

Cómo usar Blogger con un dominio personalizado (.com.ar)? [Actualizado - Junio de 2009]

.
66 comentarios

Importante:

Dado que ha habido un cambio en la configuración de dominios personalizados en Blogger, he creado este nuevo post actualizado (Junio de 2009) para reflejar esta situación. Si quieres ver la versión anterior haz clic AQUÍ.

A la hora de crear este blog, y dado que se encuentra en Blogger, la dirección original era www.pablotilli.blogspot.com, pero mi idea desde un principio fue utilizar mi propio dominio (www.pablotilli.com.ar), por lo cual tuve que pasar por varias etapas para poder lograrlo y es por esto que me decidí a escribir como hacerlo, para que ustedes también puedan asociar el suyo.

En mi caso, el dominio pablotilli.com.ar ya lo tenía registrado, pero estaba asociado con el hosting de Xmundo (servicio que recomiendo, pues en mi caso en particular, nunca tuve un problema). Asumiendo que nuestro blog ya esta creado, la idea es hacer que nuestro dominio apunte a Blogger, es por esto que el primer paso seria ingresar a NIC.ar y entrar en la zona de "trámites vía web".


Dentro de los trámites que nos permiten realizar vía web, se encuentra el que nos va a interesar si el dominio ya lo tenemos registrado: "Modificaciones de delegaciones".


Una vez dentro de la página de "Modificación de datos de delegación de un dominio" ingresamos el e-mail del responsable, el domino que queremos modificar y pulsamos "continuar".


Aquí surge un inconveniente, ya que Blogger nos pide crear un registro CNAME apuntando a ellos (ghs.google.com), pero NIC.ar no permite la creación de este tipo de registros, sólo podemos especificar los DNS de nuestro servidor.


Cuando me encontré con esta situación me puse a investigar un poco y finalmente la solución fue usar el servicio de DNS estático de CDmon. CDmon nos permite (entre otros muchos servicios) crear registros CNAME a través de su servicio gratuito. Para lograr esto, ante todo debemos registrarnos en CDMon (lo cual no tiene ninguna complejidad).

Para poder usar el servicio de CDMon volvemos a donde nos habíamos quedado en NIC.ar y donde nos permite especificar los DNS de nuestro servidor, escribimos los de CDmon y pulsamos "continuar".

ns1.cdmon.net -> 212.36.74.129

ns2.cdmon.net -> 212.36.75.129

ns3.cdmon.net -> 213.186.58.203

Ahora debemos especificar el proveedor de servicios de Internet (ISP); para esto escribimos 10dencehispahard SL, y pulsamos "buscar".

elegimos el ISP de la lista de resultados (Al dia de hoy <08-01-2008> hay dos resultados y debemos elegir el primero, el cual no termina con punto) y pulsamos "continuar".


En este punto debemos especificar el contacto técnico de CDmon: Josep Colominas. Al igual que en el caso anterior, escribimos el nombre y pulsamos "buscar".


Elegimos Josep Colominas en la lista de resultados y pulsamos "continuar".


Ahora nos mostraran una página de confirmación con todos los datos que ingresamos. Revisamos que todo este bien, y pulsamos "confirmar". Por ultimo, nos aparecerá una página avisando que NIC.ar nos ha enviado un e-mail que deberemos reenviar tal cual como lo recibimos. Una vez reenviado el e-mail, deberemos esperar aprox. 48 horas hábiles para que finalice el tramite (Si el dominio lo estamos registrando y no modificando como en mi caso, te puede tardar incluso mas de 7 días ...paciencia!!!).

Una vez que NIC.ar nos envié el e-mail avisando que el tramite ha finalizado, entramos a nuestro panel de control de CDMon, e ingresamos en la opción "DNS estático".

Dentro de la página de "Panel de control del servidor DNS estático" debemos añadir nuestro dominio como se muestra en la siguiente imagen:


El siguiente paso es la primera diferencia que hay con el metodo anterior. Al añadir nuestro dominio en CDmon, en este punto creavamos un registro CNAME, pero ahora, de las varias opciones que hay, nos interesa la que se llama "Redirección URL".


Aquí debemos especificar que el dominio principal (tu-dominio.com.ar) sea redireccionado a www.tu-dominio.com.ar. Para esto sólo debemos escribir la URL destino (www.pablotilli.com.ar en mi caso) y pulsar "guardar".


Si todo fue bien, nuestro Panel de control debería quedar como en la siguiente imagen:


Como se puede ver en la parte superior de la captura de pantalla, CDmon nos indica el tiempo estimado para que el cambio sea efectivo (en este caso faltaban 24 minutos aprox.). Hasta aquí especificamos que la dirección: "http://www.tu-dominio.com.ar" apunte a Blogger, pero aún nos falta hacer lo mismo con la dirección "http://tu-dominio.com.ar" (sin www). Para esto pulsamos sobre el botón de "Crear un registro A (un subdominio)".


Ahora nos queda por escribir el nombre del subdomino, para lo cual solo debemos escribir www, y pulsamos "guardar":

Al pulsar "guardar" volveremos a nuestro Panel de control donde veremos que se ha listado el subdominio que acabamos de agregar, pero aun falta configurarlo, por lo que dice "Por determinar". Para configurarlo pulsamos el botón de "Editar la configuración del registro" como se ve en la imagen a continuación:


De la opciones que nos aparecen para configurar nuestro subdominio, elegimos "Registro CNAME".


En esta página debemos escribir como dominio: ghs.google.com, y pulsamos "guardar".


Tras pulsar "guardar", ya esta todo listo; sólo debemos habilitar el dominio personalizado en Blogger, y esperar el tiempo que CDmon nos informa que falta para que los cambios sean efectivos. El panel de control de CDmon, finalmente debería quedarte asi:



Para habilitar el dominio personalizado en Blogger, accedemos a nuestro Blog con nuestra cuenta, y una vez dentro, elegimos la opción "Configuración".

vamos a la opciones de "Publicación",

hacemos click en la opción de "cambiar por Dominio personalizado",

escribimos nuestro dominio .com.ar (con www, ya que este es el nuevo requerimiento de Blogger para los dominios personalizados, y es el motivo de la actualizacion de este Post),


y por ultimo simplemente escribimos el texto de verificación, pulsamos "guardar configuración" y tarea cumplida.


Si algo no te quedo claro, no dudes en preguntar. Si quieres hacer alguna critica o sugerencia, espero tu comentario también.

sábado, 16 de mayo de 2009

Crear una [pequeña] aplicación completa usando wxPython (Parte 2)

.
7 comentarios

Si has llegado aquí mediante un buscador o por simple casualidad, te cuento que estas en la segunda parte de un tutorial que empieza AQUI.

Como les anticipaba en la primera parte del tutorial, en esta entrega comenzaremos a trabajar en la Ventana Principal de nuestro catálogo; pero antes de empezar con esta tarea nos concertaremos en la creación del Modelo de la aplicación.
Si bien les había comentado brevemente de que se trata el patrón MVC, a continuación les transcribo una parte del articulo que habla sobre este tema en la Wikipedia, para comprender mejor las tareas que corresponden a cada uno de los componentes (Modelo, Vista y Controlador)

“ ... Aunque se pueden encontrar diferentes implementaciones de MVC, el flujo que sigue el control generalmente es el siguiente:

1. El usuario interactúa con la interfaz de usuario de alguna forma (por ejemplo, el usuario pulsa un botón, enlace, etc.)

2. El controlador recibe (por parte de los objetos de la interfaz-vista) la notificación de la acción solicitada por el usuario. El controlador gestiona el evento que llega, frecuentemente a través de un gestor de eventos (handler) o callback.

3. El controlador accede al modelo, actualizándolo, posiblemente modificándolo de forma adecuada a la acción solicitada por el usuario (por ejemplo, el controlador actualiza el carro de la compra del usuario). Los controladores complejos están a menudo estructurados usando un patrón de comando que encapsula las acciones y simplifica su extensión.

4. El controlador delega a los objetos de la vista la tarea de desplegar la interfaz de usuario. La vista obtiene sus datos del modelo para generar la interfaz apropiada para el usuario donde se refleja los cambios en el modelo (por ejemplo, produce un listado del contenido del carro de la compra). El modelo no debe tener conocimiento directo sobre la vista. Sin embargo, el patrón de observador puede ser utilizado para proveer cierta indirección entre el modelo y la vista, permitiendo al modelo notificar a los interesados de cualquier cambio. Un objeto vista puede registrarse con el modelo y esperar a los cambios, pero aun así el modelo en sí mismo sigue sin saber nada de la vista. El controlador no pasa objetos de dominio (el modelo) a la vista aunque puede dar la orden a la vista para que se actualice. Nota: En algunas implementaciones la vista no tiene acceso directo al modelo, dejando que el controlador envíe los datos del modelo a la vista.

5. La interfaz de usuario espera nuevas interacciones del usuario, comenzando el ciclo nuevamente. ...”

Tomando este texto como referencia, nos pondremos manos a la obra y a medida que vayamos avanzando con el código, les iré haciendo notar como se relaciona lo que estemos haciendo, con lo dicho en los 5 puntos anteriores.

Codificando el Modelo

La idea aquí sera crear una clase con una serie de métodos que nos permitan interactuar con nuestra base de datos, pudiendo realizar altas, bajas, modificaciones y consultas de las películas. Si no sabes como trabajar con una base de datos en Python, puedes leer mi tutorial sobre este tema (o cualquiera de los muchos que hay en la red). Dicho esto, veamos como podría ser nuestra primera versión del Modelo.

modelo.py

import MySQLdb

class Model:

def conectar(self):
self.cnn = MySQLdb.connect(host='localhost', user='user', passwd='user', db='catalogo_peliculas_db')
self.cursor = self.cnn.cursor()

def desconectar(self):
self.cnn.close()
self.cursor.close()

def agregarPelicula(self, titulo_pelicula, anio):
self.conectar()
self.cursor.execute("INSERT INTO tblPeliculas(TituloPelicula, Anio) VALUES('" + titulo_pelicula + "'," + anio + ")")

self.desconectar()

def modificarPelicula(self, id_pelicula, titulo_pelicula, anio):
self.conectar()
self.cursor.execute("UPDATE tblPeliculas SET TituloPelicula='" + titulo_pelicula + "', Anio=" + str(anio) + " WHERE IDPelicula=" + str(id_pelicula))

self.desconectar()

def eliminarPelicula(self, id_pelicula):
self.conectar()
self.cursor.execute("DELETE FROM tblPeliculas WHERE IDPelicula=" + str(id_pelicula))

self.desconectar()

def obtenerListadoDePeliculas(self):
self.conectar()

self.cursor.execute("SELECT * FROM tblPeliculas ORDER BY TituloPelicula")

listado = self.cursor.fetchall()

self.desconectar()

return listado

Dando un rápido vistazo sobre el código, vemos que nuestra clase llamada Model, tiene seis métodos que nos permiten conectarnos y desconectarnos de la base de datos; agregar, modificar y eliminar películas, y también obtener un listado de todas las películas del catálogo. Ahora que tenemos el modelo básico, haremos una referencia a una parte del punto cuatro del artículo de la Wikipedia que les cite al principio:

“4. …. El modelo no debe tener conocimiento directo sobre la vista. Sin embargo, el patrón de observador puede ser utilizado para proveer cierta indirección entre el modelo y la vista, permitiendo al modelo notificar a los interesados de cualquier cambio. Un objeto vista puede registrarse con el modelo y esperar a los cambios, pero aun así el modelo en sí mismo sigue sin saber nada de la vista. …"

Básicamente se nos esta diciendo que si bien el Modelo NO DEBE conocer nada sobre la vista (ni tampoco sobre el Controlador), el Modelo puede utilizar algún mecanismo para informar cuando se ha producido un cambio en él. Para implementar este “sistema de avisos”, nosotros vamos a hacer uso del modulo wx.lib.pubsub; el cual nos brinda la posibilidad de usar un componente de “publicación/suscripción” donde se “publica” un cierto mensaje, y este es recibido por quienes se hayan “suscripto” a él.

Veamos como quedaría el código anterior, con la opción de que se envíe un mensaje al modificarse el Modelo.

from wx.lib.pubsub import Publisher
import MySQLdb

class Model:

def conectar(self):
self.cnn = MySQLdb.connect(host='localhost', user='user', passwd='user', db='catalogo_peliculas_db')
self.cursor = self.cnn.cursor()

def desconectar(self):
self.cnn.close()
self.cursor.close()

def agregarPelicula(self, titulo_pelicula, anio):
self.conectar()
self.cursor.execute("INSERT INTO tblPeliculas(TituloPelicula, Anio) VALUES('" + titulo_pelicula + "'," + anio + ")")

self.desconectar()

Publisher.sendMessage("pelicula_agregada", None)

def modificarPelicula(self, id_pelicula, titulo_pelicula, anio):
self.conectar()
self.cursor.execute("UPDATE tblPeliculas SET TituloPelicula='" + titulo_pelicula + "', Anio=" + str(anio) + " WHERE IDPelicula=" + str(id_pelicula))

self.desconectar()

Publisher.sendMessage("pelicula_modificada", None)

def eliminarPelicula(self, id_pelicula):
self.conectar()
self.cursor.execute("DELETE FROM tblPeliculas WHERE IDPelicula=" + str(id_pelicula))

self.desconectar()

Publisher.sendMessage("pelicula_eliminada", None)

def obtenerListadoDePeliculas(self):
self.conectar()

self.cursor.execute("SELECT * FROM tblPeliculas ORDER BY TituloPelicula")

listado = self.cursor.fetchall()

self.desconectar()

return listado
Como se puede apreciar, es muy simple enviar un mensaje avisando de que se ha producido un cambio en el Modelo, en nuestro caso, enviamos el mensaje “pelicula_agregada”, “pelicula_modificada” y “pelicula_eliminada” según corresponda; para lo cual hacemos uso del método sendMessage del objeto Publisher (que previamente hemos importado). Mas adelante veremos como hacemos para suscribirnos a estos mensajes, pero lo que se debe tener claro, es que si bien el Modelo envía los mensajes, él realmente no sabe quien los recibirá.

Hasta aquí hemos llegado por ahora con el Modelo; mas tarde le iremos agregando mayor funcionalidad a medida que vaya surgiendo la necesidad.

A continuación, empezaremos a trabajar en la Ventana Principal.

Codificando la Ventana Principal

Para codificar la Ventana Principal (y para todas las ventanas que crearemos) la debemos pensar en dos partes: la Vista y el Controlador. Teniendo esto presente, crearemos en primer lugar una clase llamada VistaPrincipal:

vistaPrincipal.py

import wx
from wx import xrc

class VistaPrincipal:
def __init__(self, app):
self.app = app

self.res = self.app.res
self.frame = self.res.LoadFrame(None, 'FramePrincipal')

def mostrar(self):
self.frame.Show()

def cargarListadoDePeliculas(self):
self.listaDePeliculas = xrc.XRCCTRL(self.frame, 'listPeliculas')

self.listaDePeliculas.SetSingleStyle(wx.LC_REPORT, True)

self.listaDePeliculas.InsertColumn(0, 'Tí­tulo', format=wx.LIST_FORMAT_LEFT, width=-1)
self.listaDePeliculas.InsertColumn(1, 'Año', format=wx.LIST_FORMAT_LEFT, width=-1)

peliculas = self.app.modelo.obtenerListadoDePeliculas()

#Cargo el listado de películas

index = 0
for
pelicula in peliculas:

item = self.listaDePeliculas.InsertStringItem (index, str(pelicula[1]))
self.listaDePeliculas.SetItemData(item, pelicula[0])

self.listaDePeliculas.SetStringItem(index, 1, str(pelicula[2]))

index+=1

self.listaDePeliculas.SetColumnWidth(0, wx.LIST_AUTOSIZE)
self.listaDePeliculas.SetColumnWidth(1, wx.LIST_AUTOSIZE)
Esta clase representa la parte gráfica de la Ventana Principal. Al ser instanciada, recibe como parámetro el objeto aplicación (que mas tarde crearemos), el cual representa la aplicación propiamente dicha, y es la que posee la información acerca de cual es el Modelo de la aplicación y nos permite acceder a los recursos graficos que carga desde el archivo XRC que creamos al principio del tutorial.

Ahora veamos en detalle los métodos de esta clase:

__init__

Aquí obtenemos los recursos gráficos desde el objeto app que recibimos como parámetro

self.app = app
self.res = self.app.res

y luego cargamos el Frame de la Ventana Principal (FramePrincipal)

self.frame = self.res.LoadFrame(None, 'FramePrincipal')

mostrar

Este método, simplemente hace visible la Ventana Principal.

self.frame.Show()

cargarListadoDePeliculas

Como el nombre del método lo indica, aquí se carga el listado de las películas. Lo primero que hacemos es obtener una referencia al objeto listPeliculas (wxListControl)

self.listaDePeliculas = xrc.XRCCTRL(self.frame, 'listPeliculas')

luego ponemos la lista en “modo reporte”

self.listaDePeliculas.SetSingleStyle(wx.LC_REPORT, True)

agregamos las columnas de Titulo y Año:

self.listaDePeliculas.InsertColumn(0, 'Título', format=wx.LIST_FORMAT_LEFT, width=-1)

self.listaDePeliculas.InsertColumn(1, 'Año', format=wx.LIST_FORMAT_LEFT, width=-1)

accedemos al Modelo para obtener el listado de las películas:

self.app.modelo.obtenerListadoDePeliculas()

cargamos las películas en la lista

index = 0
for pelicula in peliculas:
item = self.listaDePeliculas.InsertStringItem (index, str(pelicula[1]))
self.listaDePeliculas.SetItemData(item, pelicula[0])

self.listaDePeliculas.SetStringItem(index, 1, str(pelicula[2]))

index+=1

y por último, ajustamos el ancho de las columnas para que sea óptimo.

self.listaDePeliculas.SetColumnWidth(0, wx.LIST_AUTOSIZE)
self.listaDePeliculas.SetColumnWidth(1, wx.LIST_AUTOSIZE)

Esta clase esta relacionada con el punto 1 del texto que extrajimos de la Wikipedia:

“1. El usuario interactúa con la interfaz de usuario de alguna forma (por ejemplo, el usuario pulsa un botón, enlace, etc.)”

Si bien queda claro que esta clase se encarga de todo lo referido a la parte visual de la Ventana Principal, y permite que el usuario interaccione con nuestra aplicación, también queda claro que falta que de algún modo estemos a la escucha de los eventos que genera el usuario para actuar en consecuencia; por ejemplo, si hace click en el botón “Agregar” de la barra de herramientas, debería aparecer el Editor de Películas, o si pulsa el botón “Eliminar”, se debería eliminar la película seleccionada y así con todas las opciones. Aquí es donde entra en juego el Controlador, que sera el encargado de recibir los eventos generados por el usuario sobre la interface (pulsaciones de teclado, pulsaciones y movimientos del mouse, etc.) y de este manera realizar la opción solicitada.

Por ahora llegamos hasta aquí, y en la próxima parte nos meteremos de lleno en el Controlador de la Ventana Principal, y veremos como hacer que nuestra aplicación pueda ser ejecutada, y muestre esta ventana con el listado de películas cargado.

Como siempre, pueden comentar las dudas que tengan, sugerir alguna mejora, informar algun error o simplemente decir algo.

Saludos!

lunes, 4 de mayo de 2009

Crear una [pequeña] aplicación completa usando wxPython (Parte 1)

.
2 comentarios

Como les adelantaba en el post anterior, hoy comenzaré a publicar un tutorial de varias partes, en donde veremos como desarrollar una pequeña aplicación "completa" con wxPython y archivos XRC. El proyecto consistirá en realizar un catálogo de películas. El catálogo permitirá agregar, modificar y eliminar películas, así como hacer búsquedas dentro del listado. La parte gráfica la haremos haciendo uso de lo aprendido en tutoriales anteriores, usando archivos de recursos que realizaremos con wxFormBuilder y la información la guardaremos en una base de datos MySQL. Dicho esto, y sin entrar en mas detalles, empecemos a trabajar.

Estructurando la aplicación

Para estructurar nuestra aplicación, haremos uso del patrón MVC (Modelo-Vista-Controlador). Por si no sabes de que hablo, te comento brevemente de que se trata.
MVC es un patrón de diseño de software que propone dividir nuestra aplicación en tres componentes básicos: Modelo, Vista y Controlador. Esta forma de dividir la aplicación simplifica muchísimo la escalabilidad y el mantenimiento de la misma, pero también es cierto que a veces puede ser un tanto tediosa implementarla en proyectos pequeños. Si bien, nuestra aplicación entra en la categoría de proyecto pequeño, es una buena idea pensar a futuro, y generar buenos cimientos para futuras expansiones. Existen una gran cantidad de implementaciones del patrón MVC, e incluso a veces cada componente (Modelo, Vista y Controlador) pueden utilizar a su vez otro patrón de diseño en su interior, pero lo importante es comprender la idea básica detrás de MVC, y adaptarla a nuestras necesidades. A continuación veremos brevemente (y a grandes rasgos), cual es la función de cada componente del patrón MVC:

Modelo:

Este componente es el responsable de manipular los datos de nuestra aplicación. En nuestro caso será el encargado de permitirnos el acceso a una base de datos MySQL que contendrá el catálogo propiamente dicho. El modelo también es el responsable de implementar las reglas de negocio en la aplicación y es quien al producirse alguna modificación en los datos, puede comunicar este cambio a los otros componentes para que actúen en consecuencia (Por ej.: tras agregar un registro en una base de datos, se podría querer recargar el listado que esta viendo el usuario de modo que refleje los datos actualizados).

Vista:

La Vista es la encargada de presentar la información del Modelo de modo que se pueda interactuar con éste. La Vista puede quedarse a la "escucha" de cambios en el Modelo, para que al producirse cambios en él, la Vista se adapte a los nuevos datos.

Controlador:

El controlador hace de nexo entre la Vista y el Modelo, disparando acciones en respuesta a los eventos que ocurran en la aplicación, pudiendo invocar acciones en el Modelo y en la Vista.

Esta división de la aplicación en varios componentes, nos brinda una gran independencia entre los datos concretos (el Modelo) y como se ve la aplicación (la Vista), pudiendo tener varias Vistas de un mismo Modelo, y de este modo por ejemplo generar sobre un mismo Modelo, una Vista que nos permita acceder desde una PC y otra optimizada para acceder desde dispositivos móviles, o tal vez una Vista que nos permita acceder al Modelo vía una interfaz web, entre muchos otros escenarios posibles.

Este patrón de diseño no es el único, ni mucho menos, pero los demás quedan fuera del alcance de este tutorial, e incluso te invito a que profundices por ti mismo, sobre las distintas implementaciones y variaciones del patrón MVC.
Creo que con esta breve introducción, estamos en condiciones de comenzar con el desarrollo de la aplicación propiamente dicha. No aseguro que esta sea la mejor implementación de MVC; y los invito a que hagan sugerencias para mejorarla.

La Base de datos

Como ya les anticipe, para guardar los datos de nuestro catálogo haremos uso de MySQL. Nuestra base de datos será realmente muy simple, y por el momento tendrá tan sólo una tabla con tres campos.
El nombre de la base de datos será catalogo_peliculas_db y la única tabla que (por ahora) tendremos se llamará tblPeliculas. Para que vean los campos que tendrá la tabla, les muestro una captura de su estructura, vista con phpMyAdmin:

Claramente podríamos guardar muchos mas datos sobre cada película (director, elenco, nombre original, nacionalidad, etc.), pero por ahora no lo vamos a hacer para mantener la aplicación lo mas simple posible.

Ahora que ya tenemos el diseño de nuestra base de datos, pasemos a diseñar la interface gráfica de la aplicación.

La interface gráfica

Para crear la interface gráfica que le permita a los usuarios interactuar con nuestra aplicación; haremos uso (una vez mas) de wxFormBuilder. No es necesario que uses esta herramienta, sino que puedes usar cualquier otro editor de archivos XRC (incluso lo puedes hacer con un simple editor de textos). Si no sabes que es un archivo XRC o no sabes como generarlo, te invito a que leas mis tutoriales sobre organización de widgets en wxPython y manejo de archivos XRC con wxPython.

Por ahora, nuestra aplicación se compondrá sólo de dos ventanas: la "Ventana Principal" y el "Editor de Películas".

La Ventana Principal

La versión inicial de nuestra Ventana Principal será la siguiente:

Como pueden ver, nuestra Ventana Principal se compone de un menú, una barra de herramientas y una lista que muestra las películas que tenemos en nuestra base de datos.
A continuación les muestro una captura del Object Tree de wxFormBuilder para que vean claramente los widgets que la componen, y los nombres de cada uno de ellos.


El menú de nuestra aplicación desplegado se ve así:


Como se puede ver, el menú presenta las mismas opciones que la barra de herramientas, excepto la opción "Buscar" y se le añade la opción "Salir". Mas adelante, tal vez vayamos agregando nuevas opciones a nuestra interface, pero por el momento, con esto tenemos bastante para trabajar.

Ahora veamos la interfaz del Editor de Películas.

El Editor de Películas

A través del Editor de Películas, podremos agregar y modificar las películas del catálogo. Si "llamamos" a esta ventana desde la opción Agregar (ya sea desde la barra de herramientas o desde el menú), el Editor aparecerá con los campos en blanco, de modo que carguemos los datos de la película que queremos añadir al catálogo. En este caso, la pantalla aparecería así:

En cambio, si invocamos al Editor de Películas desde la opción Editar (tanto desde la barra de herramientas como desde el menú), este presentara los datos de la película seleccionada en el listado de la Ventana Principal, para de este modo, modificar la información necesaria y guardar los cambios. En este escenario, la pantalla se vería así:


Si bien tanto para agregar como para modificar una película, utilizamos el mismo editor, pueden notar que el texto del botón izquierdo cambia de Agregar a Guardar según en que modo se encuentra.

Al igual que con la Ventana Principal, a continuación les muestro como queda el Object Tree de wxFormBuilder para esta ventana:


IMPORTANTE:
Las dos ventanas estarán dentro de un mismo archivo XRC llamado gui.xrc.

Hasta aquí hicimos una breve presentación de la aplicación y de como la vamos a estructurar. En la próxima entrega comenzaremos a codificar la Ventana Principal y de este modo le iremos "dando vida" a nuestro pequeño catálogo.

Hasta la próxima!

Editado:
Ya esta disponible la parte II

domingo, 15 de marzo de 2009

Preparando un tutorial para crear una (pequeña) aplicación completa

.
2 comentarios

Esta entrada va dirigida principalmente a quienes siguen el Blog en forma frecuente, y han notado que hace varios días que no he publicado nada nuevo. Dado que varios me han enviado e-mails para saber si tenía pensado seguir publicando material sobre wxPython, y para contestarles a todos juntos; les cuento aqui que estoy escribiendo un tutorial (de varias partes) donde desarrollaremos paso a paso, una aplicación no muy grande, pero "bastante" completa. La aplicación consistirá en un pequeño catalogo de películas. El catalogo permitira agregar, modificar y eliminar películas, asi como hacer búsquedas de estas. Para guardar la información del catalogo, usaremos una base de datos MySQL y para organizar toda la aplicación haremos uso del patrón MVC (Modelo-Vista-Controlador).
Bueno, ahora ya saben lo que estoy preparando, así que en cualquier momento tendrán novedades. Si se les ocurre alguna funcionalidad mas que desearían ver en esta pequeña aplicación, haganmelo saber.

Nos vemos!

viernes, 27 de febrero de 2009

Acceso a una base de datos con Python

.
7 comentarios

En este artículo les mostrare como hacer algunas de las tareas mas típicas a la hora de trabajar con bases de datos. Veremos como realizar altas, bajas y modificaciones de datos, realizar consultas y hacer uso de transacciones.

Una de las formas mas simple para trabajar con una base de datos desde Python, es hacer uso de DB-API. DB-API es una especificación estándar de accedo a base de datos, que se compone de dos niveles: un primer nivel que funciona como una interface genérica para acceder a cualquier base de datos, y un segundo nivel compuesto por los drivers propios de cada motor de base de datos. Este esquema, nos permite lograr mayor independencia con respecto al motor de base de datos que usemos, y nos simplifica enormemente tareas como el cambio de una base de datos por otra.

Para los ejemplos usaré MySQL como motor de base de datos. Teniendo en cuenta lo dicho en el párrafo anterior, antes de empezar a trabajar, debemos instalar el driver que realmente se encargara de los detalles del acceso a MySQL. Para instalar el driver (al menos Linux) puedes hacer uso de los repositorios, ya que en las distribuciones mas populares lo podemos encontrar por defecto. El nombre del driver es MySQLdb. En el caso de Ubuntu (como es mi caso), el paquete que debemos instalar es: Python-MySQLdb.

Asumiendo que tienes instalado Python y MySQL; al instalar el driver MySQLdb, ya estamos listos para empezar a trabajar.

Trabajando con MySQLdb

Importar MySQLdb

Antes de poder conectarnos a una base de datos MySQL e interactuar con esta, debemos importar el módulo MySQLdb desde nuestro script Python:

import MySQLdb

Conectarse a la base de datos

Una vez importado el modulo MySQLdb, nos conectamos del siguiente modo:

cnn = MySQLdb.connect(host='localhost', user='usuario_mysql',passwd='password', db='base_de_datos')

Como puedes ver, para conectarnos a MySQL, usamos el método Connect() de MySQLdb, al cual le pasamos como parámetro, la dirección del servidor, el usuario, la contraseña y la base de datos. Debes tener en cuenta que esto es valido para conectarnos a MySQL, pero los parámetros de conexión difieren entre los distintos gestores de bases de datos.

Crear un cursor

Luego de conectarnos, debemos crear un cursor para poder realizar las acciones que necesitemos sobre la base de datos; para crearlo escribimos lo siguiente:

mi_cursor = cnn.cursor()

El cursor lo creamos haciendo uso del método cursor() del objeto que representa la conexión, en el ejemplo, el objeto se llama cnn, y fue instanciado como resultado de la ejecución de MySQLdb.connect() cuando nos conectamos a la base de datos.

Agregar un registro

Con el cursor creado, ya podemos interactuar con la base de datos. Para agregar un registro a la base de datos, utilizaremos el método excecute() del cursor. En realidad, este método no solo permite agregar registros, sino que lo que hace es enviar a la base de datos, el código SQL que especifiquemos como parámetro. Suponiendo que en nuestra base de datos tenemos una tabla llamada “tblArticulos” con 2 campos (“ID” y “Descripcion”), para agregar un nuevo registro escribiríamos lo siguiente:

mi_cursor.execute ("INSERT INTO tblArticulos(ID, Descripcion) VALUES(1, 'mouse')")

En este ejemplo estaríamos agregando el articulo “mouse” con ID “1”, a la tabla tblArticulos.

Modificar un registro

Para modificar un registro, procedemos igual que para agregarlo, pero obviamente debemos cambiar las sentencias SQL:

mi_cursor.execute ("UPDATE tblArticulos SET Descripcion='Mouse Logitech MX Revolution' WHERE ID=1)")

Aquí estaríamos modificando la descripción del articulo con ID “1” (el mouse que agregamos antes).

Eliminar un registro

Una vez mas, para eliminar un registro, hacemos uso del método execute() del cursor, pasándole el código SQL correspondiente a esta tarea como parámetro:

mi_cursor.execute("DELETE FROM tblArticulos WHERE ID=1)")

Aquí eliminamos el registro del articulo que creamos antes.

Consultar la base de datos

Las consultas también las hacemos con el método execute() del cursor, pero aquí nos extenderemos un poco mas en como recorrer el resultado de la consulta. Un ejemplo de consulta podría ser el siguiente:

mi_cursor.execute ("SELECT * FROM tblArticulos")

Con este código, obtendríamos todos los registros de la tabla tblArticulos. Para recorrer los distintos registros que nos devolvió la consulta, podemos elegir entre los métodos fetchone(), fetchmany() y fetchall() del cursor.

1- Usando fetchone()

res = mi_cursor.fetchone()

En el objeto res tendríamos el primer registro del resultado de la consulta representado por una tupla. Cada vez que invoquemos a este método, nos dará el registro actual e internamente quedara apuntando al siguiente, de modo que si lo invocamos sucesivas veces terminaremos por recorrer todo los registros. Para recorrer todo el resultado de la consulta, podríamos escribir algo como esto:

un_registro = mi_cursor.fetchone()

while(un_registro):
print un_registro
un_registro = mi_cursor.fetchone()

2- Usando fetchmany()

fetchmany() nos devuelve una lista de tuplas con parte del resultado de la consulta, en realidad, devolverá tantos registros como nosotros le especifiquemos. Por ejemplo, si escribimos los siguiente:
res = mi_cursor.fetchmany(3)

for reg in res:
print reg

obtendríamos los tres primeros registros del resultado de la consulta; si lo ejecutamos nuevamente, obtendríamos los tres siguientes y así sucesivamente.

3- Usando fetchall()

A diferencia de fetchmany(), fetchall() retorna todos los registros del resultado de la consulta. Al igual que fetchmany(), este método también retorna una lista de tuplas. El siguiente código, mostraría todos los registros devueltos por la consulta:

res = mi_cursor.fetchall()

for reg in res:
print reg

IMPORTANTE:
Vale aclarar que si la consulta retorna una gran cantidad de registros, este método no sería el más recomendado.

También podríamos recorrer todo el resultado de la consulta, directamente sobre el cursor (sin usar ninguno de los métodos fetch):

for reg in mi_cursor:
print reg

Como hemos visto, ninguno de los métodos anteriores nos retorna la información como un diccionario, por lo que si queremos mostrar un campo concreto (digamos “ID”) de un registro, lo deberíamos especificar por el índice de la columna y no por el nombre del campo. Si necesitamos hacer uso de esta característica, podemos especificar el tipo MySQLdb.cursors.DictCursor a la hora de crear el cursor:

mi_cursor = db.cursor(MySQLdb.cursors.DictCursor)

ahora podríamos recorrer el resultado como vimos antes, pero con la salvedad de que ahora si podemos escribir cosas como estas:

for reg in mi_cursor:
print reg['ID']

con lo cual veríamos todos los IDs de los registros devueltos por la consulta.

Para terminar con este punto, les voy a hablar de una opción interesante que tenemos a la hora de pasar nuestras sentencias SQL como parámetro del método execute(). La idea es que cuando necesitamos usar variables dentro de la consulta, estas las podemos escribir de la siguiente manera:

mi_cursor.execute ("UPDATE tblArticulos SET descripción = %s WHERE id = %s", ('Mouse genérico de 3 botones', 1))

En el ejemplo puedes ver, que ahora le estamos pasando dos parámetros al método execute(), el primero sigue siendo la consulta y el segundo es una tupla de valores, que representa, en forma posicional cada uno de los %s que existen dentro de la consulta, por lo que al enviarse la consulta anterior, internamente quedaría así:

UPDATE tblArticulos SET titulo_articulo = 'Mouse genérico de 3 botones' WHERE id = 1

Como tal vez notaste, no necesitamos poner los %s entre comillas cuando su valor sea una cadena, ya que MySQLdb lo hará por nosotros.

Manejar transacciones

Cuando alteramos el contenido de nuestra base de datos (Por ejemplo: al agregar un registro), estos cambios puede que no se reflejen inmediatamente. Por ejemplo, en caso de que estemos usando tablas del tipo MyISAM, los cambios serán aplicados inmediatamente, debido a que este tipo de tablas no soportan transacciones, pero si en cambio usáramos una tabla de tipo InnoDB (que si soporta transacciones) los cambios no se reflejaran en la misma, hasta que invoquemos el método commit() de la conexión (a no ser que la característica auto-commit esta activada). Si queremos abortar una transacción, podemos usar el método rollback() de la conexión.

Conclusión

En este artículo, intente hacer un paneo general por las acciones mas comunes al trabajar con una base de datos. Si bien he usado MySQL como motor de base de datos para los ejemplos, el proceso es prácticamente igual si usas otra base de datos, ya que como te comentaba al principio, gracias a DB-API, logramos una gran independencia del motor elegido. Con unos pocos cambios podrías hacer que los ejemplos funcionen con otro gestor de base de datos, solo debes instalar el driver correspondiente y luego importarlo desde tu aplicación. Los ejemplos que vimos son realmente muy triviales, es por esto que seguramente lo único que deberías modificar son los parámetros de conexión según corresponda.
Para terminar, te cuento que DB-API no es la única opción para trabajar con base de datos en Python. En otra oportunidad, les hablare de los denominados ORM (motores para mapeo objeto-relacional), que nos permiten acceder a las tablas de la base de datos, como si de objetos Python se tratara. Ejemplos de ORMs son SQLObject y SQLAlchemy.

Hasta la próxima!