10. Ejercicio [IMPOTS] con MySQL
![]() |
10.1. Transferencia de un archivo de texto a una tabla MySQL
El siguiente script transferirá los datos del siguiente archivo de texto:
12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:272.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062
a la tabla [impots] de la base de datos MySQL [dbimpots] siguiente:
![]() |
La conexión a la base de datos [dbimpots] se realizará con la identidad (root,"").
Vamos a utilizar la siguiente arquitectura:
![]() |
El script [console] que vamos a escribir utilizará la clase [ImpotsFile] para acceder a los datos del archivo de texto. El acceso de escritura a la base de datos se realizará con los métodos vistos anteriormente.
El código del script es el siguiente:
# -*- coding=utf-8 -*-
# importación del módulo de clases de impuestos
from impots import *
import re
# --------------------------------------------------------------------------
def copyToMysql(limites,coeffR,coeffN,HOTE,USER,PWD,BASE,TABLE):
# copia las 3 tablas numéricas de límites, coeffR, coeffN
# en la tabla TABLE de la base de datos mysql BASE
# la base mysql se encuentra en la máquina HOTE
# el usuario se identifica mediante USER y PWD
# se añaden las consultas SQL a una lista
# eliminación de la tabla
requetes=["drop table %s" % (TABLE)]
# creación de la tabla
requete="create table %s (limites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2))" % (TABLE)
requetes.append(requete)
# relleno
for i in range(len(limites)):
# consulta de inserción
requetes.append("insert into %s (limites,coeffR,coeffN) values (%s,%s,%s)" % (TABLE,limites[i],coeffR[i],coeffN[i]))
# se ejecutan las órdenes SQL
return executerCommandes(HOTE,USER,PWD,BASE,requetes,False,False)
def executerCommandes(HOTE,ID,PWD,BASE,requetes,suivi=False,arret=True):
# utiliza la conexión (HOTE,ID,PWD,BASE)
# ejecuta en esta conexión los comandos SQL contenidos en la lista de solicitudes
# si seguimiento=True, entonces cada ejecución de un comando SQL da lugar a una visualización que indica su éxito o su fracaso
# si arret=False, la función se detiene ante el primer error encontrado; de lo contrario, ejecuta todos los comandos sql
# la función devuelve una lista (número de errores, error1, error2, ...)
# conexión
try:
connexion=MySQLdb.connect(host=HOTE,user=ID,passwd=PWD,db=BASE)
except MySQLdb.OperationalError,erreur:
return [1,"Erreur lors de la connexion a MySQL sous l'identite (%s,%s,%s,%s) : %s" % (HOTE, ID, PWD, BASE, erreur)]
# se solicita un cursor
curseur=connexion.cursor()
# ejecución de las consultas SQL contenidas en la lista de consultas
# se ejecutan; al principio no hay errores
erreurs=[0]
for i in range(len(requetes)):
# se guarda la consulta en una variable local
requete=requetes[i]
# ¿Tenemos una consulta vacía?
if re.match(r"^\s*$",requete):
continue
# ejecución de la consulta i
erreur=""
try:
curseur.execute(requete)
except Exception, erreur:
pass
# ¿Ha habido algún error?
if erreur:
# otro error
erreurs[0]+=1
# mensaje de error
msg="%s : Erreur (%s)" % (requete[0:len(requete)-1],erreur)
erreurs.append(msg)
# ¿seguimiento en pantalla o no?
if suivi:
print msg
# ¿se detiene?
if arret:
return erreurs
else:
if suivi:
# ¿se muestra la consulta sin su marca de fin de línea?
print "%s : Execution reussie" % (cutNewLineChar(requete))
# información sobre el resultado de la consulta ejecutada
afficherInfos(curseur)
# cierre de la conexión
try:
connexion.commit()
connexion.close()
except MySQLdb.OperationalError,erreur:
# otro error
erreurs[0]+=1
# mensaje de error
msg="%s : Erreur (%s)" % (requete,erreur)
erreurs.append(msg)
# retorno
return erreurs
# ------------------------------------------------ principal
# identidad del usuario
USER="root"
PWD=""
# la máquina host del SGBD
HOTE="localhost"
# identidad de la base
BASE="dbimpots"
# identidad de la tabla de datos
TABLE="impots"
# el archivo de datos
IMPOTS="impots.txt"
# instanciación de la capa [dao]
try:
dao=ImpotsFile(IMPOTS)
except (IOError, ImpotsError) as infos:
print ("Une erreur s'est produite : {0}".format(infos))
sys.exit()
# se transfieren los datos recuperados a una tabla mysql
erreurs=copyToMysql(dao.limites,dao.coeffR,dao.coeffN,HOTE,USER,PWD,BASE,TABLE)
if erreurs[0]:
for i in range(1,len(erreurs)):
print erreurs[i]
else:
print "Transfert opere"
# fin
sys.exit()
Notas:
- líneas 106-110: se instancia la clase [ImpotsFile] presentada en el apartado 8.1;
- línea 113: las tablas de límites, coeffR y coeffN, se transfieren a una base MySQL;
- línea 8: la función copyToMysql ejecuta esta transferencia. La función copyToMysql crea una tabla de consultas a ejecutar y las ejecuta mediante la función executerCommandes, línea 25;
- líneas 28-89: la función executerCommandes es la ya presentada anteriormente, en el apartado 9.7, con una diferencia: en lugar de estar en un archivo de texto, las consultas se encuentran en una lista;
El archivo de texto impots.txt:
12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:272.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062
Resultados en pantalla:
Verificación con phpMyAdmin:
![]() |
10.2. El programa de cálculo de impuestos
Ahora que los datos necesarios para el cálculo del impuesto se encuentran en una base de datos, podemos escribir el script de cálculo del impuesto. Volvemos a utilizar una arquitectura de tres capas:
![]() |
La nueva capa [dao] se conectará a SGBD y MySQL, y será implementada por la clase [ImpotsMySQL]. Ofrecerá a la capa [metier] la misma interfaz que antes, compuesta por el único método getData que devuelve la tupla (límites, coeffR, coeffN). Por lo tanto, la capa [metier] no cambiará con respecto a la anterior version.
10.3. La clase [ImpotsMySQL]
La capa [dao] ahora está implementada por la siguiente clase [ImpotsMySQL] (archivo impots.py):
class ImpotsMySQL:
# constructor
def __init__(self,HOTE,USER,PWD,BASE,TABLE):
# inicializa los atributos de límites, coeffR, coeffN
# los datos necesarios para el cálculo del impuesto se han colocado en la tabla mysqL TABLE
# perteneciente a la base BASE. La tabla tiene la siguiente estructura
# límites decimal(10,2), coeffR decimal(10,2), coeffN decimal(10,2)
# la conexión a la base de datos mysql de la máquina HOTE se realiza con la identidad (USER,PWD)
# lanza una excepción si se produce un error
# conexión a la base de datos mysql
connexion=MySQLdb.connect(host=HOTE,user=USER,passwd=PWD,db=BASE)
# se solicita un cursor
curseur=connexion.cursor()
# lectura en bloque de la tabla TABLE
requete="select limites,coeffR,coeffN from %s" % (TABLE)
# ejecuta la consulta [requete] en la base [base] de la conexión [connexion]
curseur.execute(requete)
# procesamiento del resultado de la consulta
ligne=curseur.fetchone()
self.limites=[]
self.coeffR=[]
self.coeffN=[]
while(ligne):
# línea actual
self.limites.append(ligne[0])
self.coeffR.append(ligne[1])
self.coeffN.append(ligne[2])
# línea siguiente
ligne=curseur.fetchone()
# desconexión
connexion.close()
def getData(self):
return (self.limites, self.coeffR, self.coeffN)
Notas:
- línea 18: la consulta SQL SELECT que solicita los datos de la base de datos MySQL. Las líneas de resultados de SELECT son procesadas posteriormente una a una por [curseur.fetchone] (líneas 22 y 32) para crear las tablas de límites, coeffR, coeffN (líneas 28-30);
- el método getData de la interfaz de la capa [dao].
10.4. El script de consola
El código del script de consola (impots_04) es el siguiente:
# -*- coding=utf-8 -*-
# importación del módulo de las clases Impuestos*
from impots import *
# ------------------------------------------------ main
# la identidad del usuario
USER="root"
PWD=""
# la máquina host del SGBD
HOTE="localhost"
# identidad de la base de datos
BASE="dbimpots"
# identidad de la tabla de datos
TABLE="impots"
# archivo de entrada
DATA="data.txt"
# archivo de salida
RESULTATS="resultats.txt"
# instanciación de la capa [metier]
try:
metier=ImpotsMetier(ImpotsMySQL(HOTE,USER,PWD,BASE,TABLE))
except (IOError, ImpotsError) as infos:
print ("Une erreur s'est produite : {0}".format(infos))
sys.exit()
# los datos necesarios para el cálculo del impuesto se han colocado en el archivo IMPOTS
# a razón de una línea por tabla en el formato
# val1:val2:val3,...
# lectura de los datos
try:
data=open(DATA,"r")
except:
print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit()
# apertura del archivo de resultados
try:
resultats=open(RESULTATS,"w")
except:
print "Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit()
# utilidades
u=Utilitaires()
# se procesa la línea actual del archivo de datos
ligne=data.readline()
while(ligne != ''):
# se elimina el posible carácter de fin de línea
ligne=u.cutNewLineChar(ligne)
# se recuperan los 3 campos «casado:hijos:salario» que forman la línea
(marie,enfants,salaire)=ligne.split(",")
enfants=int(enfants)
salaire=int(salaire)
# se calcula el impuesto
impot=metier.calculer(marie,enfants,salaire)
# se introduce el resultado
resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
# se lee una nueva línea
ligne=data.readline()
# se cierran los archivos
data.close()
resultats.close()
Notas:
- línea 23: instanciación de las capas [dao] y [metier];
- el resto del código es conocido.
Los mismos que con las versiones anteriores del ejercicio.



