Skip to content

10. تمرين [حساب الضرائب] باستخدام MySQL

10.1. نقل ملف نصي إلى جدول MySQL

سيقوم البرنامج النصي التالي بنقل البيانات من الملف النصي التالي:

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

في جدول [impots] لقاعدة بيانات MySQL التالية [dbimpots]:

 

سيتم إجراء الاتصال بقاعدة البيانات [dbimpots] باستخدام بيانات الاعتماد (root، "").


البرنامج (impotstxt2mysql)

سنستخدم البنية التالية:

سيستخدم البرنامج النصي [console] الذي سنكتبه فئة [ImpotsFile] للوصول إلى البيانات الموجودة في الملف النصي. وسيتم تنفيذ الوصول للكتابة إلى قاعدة البيانات باستخدام الطرق التي تمت مناقشتها سابقًا.

فيما يلي كود البرنامج النصي:

#    -*- coding=utf-8 -*-

#    import of Impots class module
from impots import *
import re

# --------------------------------------------------------------------------
def copyToMysql(limites,coeffR,coeffN,HOTE,USER,PWD,BASE,TABLE):
    #  copy the 3 numerical limit tables, coeffR, coeffN
    #  in table TABLE of mysql database BASE
    #  the mysql database is on machine HOTE
    #  the user is identified by USER and PWD

    #  put SQL queries in a list
    #    deletion table
    requetes=["drop table %s" % (TABLE)]
    #    table creation
    requete="create table %s (limites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2))" % (TABLE)
    requetes.append(requete)
    #    filling
    for i in range(len(limites)):
        #  insertion request
        requetes.append("insert into %s (limites,coeffR,coeffN) values (%s,%s,%s)" % (TABLE,limites[i],coeffR[i],coeffN[i]))
    #    execute SQL orders
    return executerCommandes(HOTE,USER,PWD,BASE,requetes,False,False)


def executerCommandes(HOTE,ID,PWD,BASE,requetes,suivi=False,arret=True):
    #    uses connection (HOTE,ID,PWD,BASE)
    #  executes on this connection the SQL commands contained in the request list
    #  if followed=True then each execution of a SQL order is displayed, indicating success or failure
    #  if arret=False, the function stops on the 1st error encountered, otherwise it executes all sql commands
    #  the function returns a list (no. of errors, error1, error2, ...)

    #    connection
    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)]

    #  a cursor is requested
    curseur=connexion.cursor()
    #  execute SQL requests contained in the request list
    #    we run them - initially no errors
    erreurs=[0]
    for i in range(len(requetes)):
        #  put the query in a local variable
        requete=requetes[i]
        #    do we have an empty query?
        if re.match(r"^\s*$",requete):
            continue
        #    query execution i
        erreur=""
        try:
            curseur.execute(requete)
        except Exception, erreur:
            pass
        #    was there a mistake?
        if erreur:
            #    one more mistake
            erreurs[0]+=1
            #  error msg
            msg="%s : Erreur (%s)" % (requete[0:len(requete)-1],erreur)
            erreurs.append(msg)
            #  screen tracking or not?
            if suivi:
                print msg
            #    shall we stop?
            if arret:
                return erreurs
        else:
            if suivi: 
                #  the query is displayed without its end-of-line marker
                print "%s : Execution reussie" % (cutNewLineChar(requete))
                #  information on the result of the query
                afficherInfos(curseur)
    #    locking connection
    try:
        connexion.commit()
        connexion.close()
    except MySQLdb.OperationalError,erreur:
        #    one more mistake
        erreurs[0]+=1
        #  error msg
        msg="%s : Erreur (%s)" % (requete,erreur)
        erreurs.append(msg)

    #    return
    return erreurs


#    ------------------------------------------------ main
#    user identity
USER="root"
PWD=""
#  the sgbd host machine
HOTE="localhost"
#    base identity
BASE="dbimpots"
#    data table identity
TABLE="impots"
#  the data file
IMPOTS="impots.txt"

#    layer instantiation [dao]
try:
    dao=ImpotsFile(IMPOTS)
except (IOError, ImpotsError) as infos:
    print ("Une erreur s'est produite : {0}".format(infos))
    sys.exit()

#  transfer the recovered data to a mysql table
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"
#    end
sys.exit()

ملاحظات:

  • الأسطر 106–110: نقوم بإنشاء مثيل لفئة [ImpotsFile] المعروضة في القسم 8.1؛
  • السطر 113: يتم نقل المصفوفات limites و coeffR و coeffN إلى قاعدة بيانات MySQL؛
  • السطر 8: تقوم الدالة copyToMysql بتنفيذ هذا النقل. تقوم الدالة copyToMysql بإنشاء مصفوفة من الاستعلامات المطلوب تنفيذها وتقوم بتنفيذها بواسطة الدالة executerCommandes، السطر 25؛
  • الأسطر 28–89: دالة executerCommandes هي الدالة التي تم عرضها سابقًا في القسم 9.7، مع اختلاف واحد: بدلاً من أن تكون الاستعلامات في ملف نصي، فإنها موجودة في قائمة؛

النتائج

الملف النصي 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

نتائج الشاشة:

Transfert opéré

التحقق باستخدام phpMyAdmin:

 

10.2. برنامج حساب الضرائب

الآن بعد أن أصبحت البيانات اللازمة لحساب الضريبة موجودة في قاعدة البيانات، يمكننا كتابة البرنامج النصي لحساب الضريبة. ونحن نستخدم مرة أخرى بنية ثلاثية المستويات:

ستتصل الطبقة [dao] الجديدة بنظام إدارة قواعد البيانات MySQL وسيتم تنفيذها بواسطة فئة [ImpotsMySQL]. وستزود الطبقة [business] بنفس الواجهة السابقة، والتي تتكون من طريقة getData الوحيدة التي تُرجع التوبلة (limits, coeffR, coeffN). وبالتالي، ستبقى الطبقة [business] دون تغيير عن الإصدار السابق.

10.3. فئة [ImpotsMySQL]

يتم الآن تنفيذ طبقة [dao] بواسطة فئة [ImpotsMySQL] التالية (ملف impots.py):

class ImpotsMySQL:

    #    manufacturer
    def __init__(self,HOTE,USER,PWD,BASE,TABLE):
        #    initializes limit attributes, coeffR, coeffN
        #  the data required to calculate the tax has been placed in table mysqL TABLE
        #  belonging to the BASE database. The table has the following structure
        #    limits decimal(10,2), coeffR decimal(10,2), coeffN decimal(10,2)
        #  connection to the mysql database on machine HOTE is made as (USER,PWD)
        #  throws an exception if an error occurs

        #    connection to mysql database
        connexion=MySQLdb.connect(host=HOTE,user=USER,passwd=PWD,db=BASE)
        #  a cursor is requested
        curseur=connexion.cursor()

        #    block reading of table TABLE
        requete="select limites,coeffR,coeffN from %s" % (TABLE)
        #  executes the query [requete] on the base [base] of the connection [connexion]
        curseur.execute(requete)
        #    query result evaluation
        ligne=curseur.fetchone()
        self.limites=[]
        self.coeffR=[]
        self.coeffN=[]
        while(ligne):
            #  current line
            self.limites.append(ligne[0])
            self.coeffR.append(ligne[1])
            self.coeffN.append(ligne[2])
            #  next line
            ligne=curseur.fetchone()
        #    disconnect
        connexion.close()

    def getData(self):
        return (self.limites, self.coeffR, self.coeffN)

ملاحظات:

  • السطر 18: استعلام SQL SELECT الذي يسترد البيانات من قاعدة بيانات MySQL. ثم تتم معالجة صفوف النتائج من SELECT واحدًا تلو الآخر باستخدام [cursor.fetchone] (السطران 22 و32) لإنشاء المصفوفات limits وcoeffR وcoeffN (السطور 28–30)؛
  • طريقة getData لواجهة طبقة [dao].

10.4. نص برمجي وحدة التحكم

فيما يلي كود البرنامج النصي لوحدة التحكم (impots_04):

#    -*- coding=utf-8 -*-

#    import of Impots* class module
from impots import *

#    ------------------------------------------------ main
#    user identity
USER="root"
PWD=""
#  the sgbd host machine
HOTE="localhost"
#    base identity
BASE="dbimpots"
#    data table identity
TABLE="impots"
#    input file
DATA="data.txt"
#    output file
RESULTATS="resultats.txt"

#    instantiation layer [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()

#  the data required to calculate the tax has been placed in the IMPOTS file
#  one line per table in the form
#    val1:val2:val3,...

#    reading data
try:
    data=open(DATA,"r")
except:
    print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
    sys.exit()

#    open results file
try:
    resultats=open(RESULTATS,"w")
except:  
    print "Impossible de creer le fichier des résultats [RESULTATS]"
    sys.exit()

#    utilities
u=Utilitaires()

#  use the current line of the data file
ligne=data.readline()
while(ligne != ''):
    #  remove any end-of-line marker
    ligne=u.cutNewLineChar(ligne)
    #  we retrieve the 3 fields married:children:salary which form the line
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    #  tax calculation
    impot=metier.calculer(marie,enfants,salaire)
    #  enter the result
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    #  a new line is read
    ligne=data.readline()
#    close files
data.close()
resultats.close()

ملاحظات:

  • السطر 23: إنشاء مثيلات لطبقتي [dao] و[business
  • باقي الكود مألوف.

النتائج

مثلما هو الحال في الإصدارات السابقة من التمرين.