I. Introduction▲
L'absence de composants natifs aux bases de données sous une version personnelle est un des freins importants
à ceux qui souhaitent s'initier à Delphi. Une solution consiste à passer par un autre langage. Ce langage est Python,
un langage objet, open source et interprété très puissant. Les composants PythonForDelphi permettent d'utiliser
des objets Python sous Delphi.
Ce tutoriel est destiné aux programmeurs Delphi d'une version personnelle qui souhaitent utiliser malgré tout des bases de données.
Sachez qu'aucune connaissance en Python n'est exigé. Tout le code que vous écrirez sera exclusivement en Delphi.
En revanche, on ne pourra utiliser les composants du style (DBListBox, DBComboBox, DBGrid ...) vu que l'on travaille sous une version personnelle de Delphi.
Tout se fera par requête SQL et exploitation de ces requêtes.
Ecrit en juillet 2005, ce tutoriel a été revue en novembre 2006 pour être compatible avec les dernières versions
des logiciels/bibliothèques actuellement disponible (notamment python 2.5 et Firebird 2.0)
II. Installation des composants▲
Vous pouvez télécharger le source complet des exemples ici. Il a été écrit sous Delphi 7 édition personnelle mais a également été testé sous Delphi 2005 édition personnelle (win 32). Ce fichier contient:
- le source de l'exemple
- l'exécutable de l'exemple
- le runtime FBruntimePython contenant le moteur Python et les dépendances pour Firebird
- le fichier FBBase.py, interface permettant de manipuler des bases Firebird
Aperçu de l'interface de l'exemple:
II-A. Installation de la bibliothèque PythonForDelphi▲
La première chose est d'installer la bibliothèque PythonForDelphi. L'installation est très facile.
Il suffit de récupérer l'installateur ici.
La version utilisée pour ce tutoriel est la version 3.32. Ensuite lancez l'exécutable et suivez les instructions.
Le répertoire par défaut est c:\Program Files\PythonForDelphi:
Arrivé à cette fenêtre,
cliquez tout d'abord sur le bouton Edit Definition.inc, commentez la ligne 41 {$DEFINE PREFER_UNICODE} // this will convert a variant containing an OleStr to a UniCode Python string.,
puis enregistrez le fichier. Vous pourrez toujours remodifier ce fichier plus tard que vous retrouverez dans le répertoire
./Components/Sources/Core. C'est également ce fichier qui vous permettra de pouvoir compiler vos programmes Delphi
avec différentes version de Python.
sélectionnez ensuite votre version de Delphi et la version 2.5
de Python puis cliquez sur le bouton Compile. Cela installera les composants dans l'IDE de Delphi. Si vous avez une version
personnelle de Delphi, une erreur apparaîtra dans les logs,
car tous les composants n'auront pas été installés (certains nécessitant une version professionnelle).
Arrivé à la fenêtre suivante, cliquez directement sur Cancel.
En ouvrant l'IDE de Delphi 7, vous aurez un nouvel onglet qui contiendra au moins ces icônes:

Et sous Delphi 2005:

Présentation succincte des composants. Beaucoup sont encore présents pour raison historique.
Composant | Description |
---|---|
PythonGUIInputOutput | Ce composant permet de rediriger la sortie de l'exécution d'un code Python vers un TMemo ou un TRichEdit. |
AtomPythonEngine | Composant déprécié à partir de Delphi 6. Utiliser le composant PythonEngine |
PythonEngine | Moteur Python - permet d'utiliser d'autres composants de PythonForDelphi |
PythonInputOutput | Ce composant permet de rediriger la sortie de l'exécution d'un code Python vers ce que l'on veut |
PythonType | Ce composant permet de créer un nouveau type Objet. |
PythonModule | Ce composant permet de créer un nouveau module. On peut également s'en servir pour stocker son propre code python qui sera inclus dans le .exe pour ne pas avoir à distribuer des fichiers .py en annexe. |
PythonDelphiVar | Ce composant permet de créer des variables Python qui seront également accessibles depuis Delphi |
PyDelphiWrapper | Ce composant (apparaissant dans la version 3.29) permet d'exporter des variables Delphi |
PythonDatabase | Ce composant (présent avec version commerciale de Delphi) implémente les unités VCL DB et DBTables pour l'accès à une base de données |
II-B. Installation de Firebird 2.0▲
Le serveur utilisé était d'une version 2.0RC5. Vous pouvez le télécharger directement sur le site de Firebird.
II-C. Installation des dépendances Python▲
Vous avez à ce stade 2 possibilités pour votre développement et pour le déploiement du logiciel.
Vous pouvez opter pour l'installation complète du langage Python et des librairies utiles (comptez 30 Mo en tout)
ou bien simplement un runtime (4 Mo) à installer dans le répertoire de l'application.
Pour l'installation, c'est très simple, il suffit de récupérer les installateurs auto extractibles disponibles sur les
sites dont vous trouverez les adresses ici.
Langages et librairies utilisés lors du développement de ce tutoriel:
- Python 2.5
- kinterbasdb 3.2.0
Si vous optez pour le runtime, il suffit de décompresser l'archive disponible ici dans le répertoire de l'application.
Ce runtime (assez compliqué à créer) est figé dans le sens où il a été construit à partir de Python 2.5 et kinterbasdb 3.2.0 et qu'il n'est pas
soumis à l'arrivée de nouvelles versions de ces librairies. Cependant des mises à jour seront faites si nécessaire.
Si vous pensez modifier les sources Python, pensez à installer Python 2.5 qui fournit un éditeur adapté à la gestion
des sources Python.
Si de plus, vous souhaitez utiliser d'autres objets Python avec Delphi, il est préférable d'installer le langage Python plutôt que d'utiliser
le runtime que je vous fournis.
II-D. Installation du fichier FBBase.py▲
Il suffit de copier ce fichier à la racine du répertoire de l'application. Ce fichier correspond à l'interface Python avec la base de données Firebird.
II-E. Tableau récapitulatif▲
Développement (version Runtime) | Développement (version Full) | Deploiement (version Runtime) | Deploiement (version Full) |
---|---|---|---|
Delphi 7/2005 | Delphi 7/2005 | Exécutable de l'application | Exécutable de l'application |
PythonForDelphi 3.32 | PythonForDelphi 3.32 | ||
Firebird 2.0 | Firebird 2.0 | Firebird 2.0 | Firebird 2.0 |
FBBase.py | FBBase.py | FBBase.py | FBBase.py |
FBruntimePython | Python 2.5 | FBruntimePython | Python 2.5 |
kinterbasdb 3.2.0 | kinterbasdb 3.2.0 |
III. Python et les bases de données▲
III-A. L'API 2.0 de Python pour les bases de données (DBAPI)▲
III-A-1. Introduction▲
Il n'est pas possible d'accéder en natif aux bases de données avec Python. Cependant l'ajout de bibliothèques
conformes au standard DBAPI permet d'accéder à différentes bases de données.
On peut citer par exemple les modules kinterbasdb pour accéder aux bases Firebird/Interbase,
mySQLdb pour les bases Mysql, psycopg pour les bases PostgreSQL ...
Ce standard présenté par la suite permet d'accéder à différents types de bases de données sans grandes modifications
de votre code. Une explication au chapitre V vous guidera si vous optez pour une autre BDD.
III-A-2. La fonction connect▲
La fonction connect permet la connexion à une base de données. Le
standard DBAPI recommande d'utiliser les paramètres suivants:
database: Nom de la base de données à laquelle on veut se connecter
dsn: Nom de la source de données utilisée pour la connexion
host: Nom de la machine sur laquelle s'exécute la base de données
password: Mot de passe pour la connexion
user: Nom d'utilisateur pour la connexion
La fonction connect renvoie un objet de la classe Connection
Python est sensible à la casse. Les minuscules sont différentes des majuscules. Lorsque vous utiliserez des objets Python dans votre programme Delphi, il faudra également se souvenir que cette distinction est encore en vigueur.
import
kinterbasdb
con =
kinterbasdb.connect
(
host=
'
localhost
'
, database=
r'
C:\Program
Files\Firebird\Firebird_2_0\examples\empbuild\employee.fdb
'
, \
user=
'
sysdba
'
, password=
'
masterkey
'
)
III-A-3. Classe Connection▲
4 méthodes de la classe Connection vont nous intéresser:
close(): Ferme la connexion à la base de données et libère les ressources
commit(): Applique la transaction courante à la base de données
cursor(): Renvoie une instance de la classe Cursor
rollback(): Annule la transaction courante sur la base de données
cur =
con.cursor
(
)
III-A-4. Classe Cursor▲
Une instance de la classe Cursor représente l'ensemble des résultats d'une requête SQL.
Cette classe fournit de nombreuses méthodes. Nous ne présenterons que celles utilisées par la suite.
close(): Ferme le curseur et libère les ressources associées
execute(statement): Exécute une requête SQL statement sur la base de données
fetchall(): Renvoie le résultat de la requête sous forme d'une liste de tuples
Remarque: Un tuple est une séquence d'éléments immutables tandis qu'une liste est une séquence d'éléments mutables
cur.execute
(
'
select
*
from
Country
'
)
l =
cur.fetchall
(
)
print
l
cur.close
(
)
III-B. Le module FBBase.py - interface avec la BDD Firebird▲
III-B-1. Introduction▲
Pour utiliser les modules fournis avec Python sur les bases de données, nous avions 3 possibilités. La première
possibilité serait d'utiliser les objets de la classe Connection et Cursor de façon brut. Mais en général, quelque
soit la base de données utilisée, on se crée une interface qui nous facilite l'utilisation de ces classes. Ici, cette
interface peut se faire du côté de Delphi ou du côté de Python. J'ai opté pour la programmer en Python pour
les raisons suivantes:
- Il est plus simple de manipuler les objets Python avec Python qu'avec Delphi
- Certains paramètres (notamment lors de la connexion à la base de données) entraînent
une erreur de compilation sous Delphi car termes non reconnus. Donc à moins de s'en sortir de manière peu propre, il était préférable de tout
faire en Python et de gérer sous Delphi des objets Python que l'on maîtrise entièrement.
Néanmoins, l'interface proposée est une interface simple et minimaliste à l'exception de quelques fonctions. Elle pourra donc être
complétée directement pour les besoins d'une base de données spécifique. Une autre possibilité est de se créer une nouvelle interface
sous Delphi qui gérera la base de données en question en se liant à celle sous python qui fournit tous les outils unitaires à l'utilisation
d'une base de données.
III-B-2. L'objet TFBConnection▲
import
kinterbasdb
try
:
if
kinterbasdb.FB_API_VER =
=
20
: kinterbasdb.init
(
type_conv=
200
) #
#
Firebird
2.0.x
except
: pass
import
os.path
import
os
class
TFBConnection:
def
__init__
(
self, host=
'
localhost
'
, pathbase=
r'
C:\Program
Files\Firebird\Firebird_2_0\examples\empbuild\employee.fdb
'
, \
user=
'
sysdba
'
, password=
'
masterkey
'
):
self.pathbase=
pathbase
self.host=
host
self.user=
user
self.password=
password
def
Initialize
(
self, host=
'
localhost
'
, pathbase=
r'
C:\Program
Files\Firebird\Firebird_2_0\examples\empbuild\employee.fdb
'
, \
user=
'
sysdba
'
, password=
'
masterkey
'
):
self.pathbase=
pathbase
self.host=
host
self.user=
user
self.password=
password
def
Connect
(
self): self.con =
kinterbasdb.connect
(
host=
self.host, database=
self.pathbase, user=
self.user, password=
self.password)
def
Commit
(
self): self.con.commit
(
)
def
Cursor
(
self): return
TFBCursor
(
self)
def
Rollback
(
self): self.con.rollback
(
)
def
Close
(
self): self.con.close
(
)
#
#
Fonctionnalite
propre
a
Firebird
def
DropDatabase
(
self): self.con.drop_database
(
)
def
CreateDatabase
(
self):
if
self.host=
=
'
localhost
'
:
try
: os.makedirs
(
os.path.dirname
(
self.pathbase))
except
: pass
else
:
try
: os.makedirs
(
os.path.dirname
(
'
\\
\\
'
+
self.host+
self.pathbase))
except
: pass
self.con =
kinterbasdb.create_database
(
"
create
database
'
"
+
self.pathbase+
"
'
user
'
"
+
self.user+
"
'
password
'
"
+
\
self.password+
"
'
"
)
Cette classe est une interface à la classe Connection et à la fonction connect présentée précédemment. Elle
permet de gérer une connexion à une BDD en reprenant les principales fonctions.
Tout d'abord, les 3 premières lignes servent à l'importation de modules, kinterbasdb pour la gestion des bases Firebird,
os et os.path pour la gestion des fichiers.
Présentation ensuite les méthodes de la classe TFBConnection:
- __init__(self, host, database, user, password): Méthode appelée à la création de l'objet. Initialise les paramètres de la classe.
- Connect(self): Lance la connexion à la BDD.
- Commit(self): Applique la transaction courante à la base de données.
- Cursor(self): Renvoie un objet de la classe TFBCursor.
- Rollback(self): Annule la transaction courante sur la base de données.
- Close(self): Ferme la connexion à la base de données et libère les ressources.
- DropDatabase(self): Efface la base de données.
- CreateDatabase(self): Crée la base de données. On créé si nécessaire le répertoire où sera sauvegardée la base.
pyCon =
TFBConnection
(
)
pyCon.Connect
(
)
III-B-3. L'objet TFBCursor▲
class
TFBCursor
(
kinterbasdb.Cursor):
def
__init__
(
self, FBConnection): kinterbasdb.Cursor.__init__
(
self, FBConnection.con)
def
ExecuteElem
(
self, strreq): return
(
self.ExecuteListe
(
strreq))[0
]
def
ExecuteElem2
(
self, strreq): return
(
self.ExecuteTuple
(
strreq))[0
]
def
ExecuteTuple
(
self, strreq):
self.execute
(
strreq)
return
self.fetchall
(
)
def
ExecuteIter
(
self, strreq):
self.execute
(
strreq)
return
self.iter(
)
def
ExecuteListe
(
self, strreq):
listresult=
[]
for
laliste in
self.ExecuteTuple
(
strreq): listresult.append
(
laliste[0
])
return
listresult
#
#
Fonctions
clone
de
celles
de
base
-
permet
d'avoir
des
references
explicites
dans
ce
code
def
Close
(
self): self.close
(
)
def
Execute
(
self, strreq): self.execute
(
strreq)
def
IterMap
(
self): return
self.itermap
(
)
def
RowCount
(
self): return
self.rowcount
(
)
def
FecthAll
(
self): return
self.fetchall
(
)
def
FecthOne
(
self): return
self.fetchone
(
)
def
Description
(
self): return
self.description
(
)
def
CallProc
(
self, procname, params=
(
)): return
self.callproc
(
procname, params)
#
#
Fonctionnalites
supplementaires
propres
a
Firebird
def
ExecuteElemMap
(
self, strreq): return
(
self.ExecuteMap
(
strreq))[0
]
def
ExecuteMap
(
self, strreq):
self.execute
(
strreq)
return
self.fetchallmap
(
)
def
ExecuteIterMap
(
self, strreq):
self.execute
(
strreq)
return
self.itermap
(
)
def
ListeTable
(
self):
return
self.ExecuteListe
(
"
select
rdb
$
relation_name
from
rdb
$
relations
where
"
+
\
"
rdb
$
relation_name
not
like
'
RDB
$
%
'
;
"
)
def
ListeChamp
(
self, strtable):
l =
self.ExecuteListe
(
"
Select
RDB
$
FIELD_NAME
from
RDB
$
RELATION_FIELDS
"
+
\
"
where
RDB
$
RELATION_NAME
=
'
"
+
strtable.upper
(
)+
"
'
;
"
)
for
i in
range(
len(
l)): l[i] =
l[i].strip
(
) #
#
La
requete
precedente
laisse
des
espaces
a
la
fin
des
noms
return
l
def
CreateGenerator
(
self, strgen, strtrig, strtable, strcolumn):
self.execute
(
"
CREATE
GENERATOR
"
+
strgen+
"
;
"
)
strSQL=
"
CREATE
TRIGGER
"
+
strtrig+
"
FOR
"
+
strtable+
\
"
ACTIVE
BEFORE
INSERT
POSITION
0
"
+
\
"
AS
BEGIN
"
+
\
"
IF
(
NEW
.
"
+
strcolumn+
"
IS
NULL
)
THEN
"
+
\
"
NEW
.
"
+
strcolumn+
"
=
GEN_ID
(
"
+
strgen+
"
,
1
)
;
"
+
\
"
END
"
self.execute
(
strSQL)
Cette classe est une interface à la classe Cursor présentée précédemment. Elle permet de manière simple
d'exécuter des requêtes et de récupérer les résultats avec pour seule connaissance requis, le langage SQL.
Présentation de quelques méthodes de la classe TFBCursor:
- __init__(self, FBConnection): Méthode appelée lors de la construction de l'objet
- Close(self): Ferme le curseur. Vous pouvez également utiliser close (sans le c majuscule)
- Execute(self, strreq): Exécute la requête SQL strreq. A utiliser sur des requêtes ne retournant aucun résultat tel que INSERT, UPDATE, ... Vous pouvez aussi utiliser la méthode execute (sans le e majuscule).
- ExecuteElem(self, strreq): A utiliser pour récupérer le résultat unique d'une requête sur un seul champ.
- ExecuteElem2(self, strreq): A utiliser pour récupérer le tuple unique d'une requête sur un seul champ.
- ExecuteTuple(self, strreq): Exécute la requête SQL strreq et renvoie le résultat sous forme d'une liste de tuples. A utiliser sur une requête SELECT.
- ExecuteMap(self, strreq): Exécute la requête SQL strreq et renvoie le résultat sous forme d'une liste de map (ou dictionnaire). A utiliser sur une requête SELECT.
- ExecuteListe(self, strreq): Exécute la requête SQL strreq et renvoie le résultat sous forme d'une liste de valeurs. A utiliser sur une requête SELECT qui ne contient qu'un seul champ de retour.
- ListeTable(self): Retourne une liste des tables de la base de données. La requête utilisée n'est compatible qu'avec Firebird.
- ListeChamp(self, strtable): Retourne une liste des champs de la table strtable de la base de données. La requête utilisée n'est compatible qu'avec Firebird.
- CreateGenerator(self, strgen, strtrig, strtable, strcolumn): Permet d'appliquer à un champ une auto-incrémentation. strtable et strcolumn correspondent à la table et au champ en question. strgen et strtrig correspondent au nom du générateur et du trigger
Pour les requête du type SELECT, vous aurez le choix entre les méthodes ExecuteTuple et ExecuteMap. La première vous donnera un code plus concis, la deuxième un code plus clair.
>
>
>
pyCon =
TFBConnection
(
)
>
>
>
pyCon.Connect
(
)
>
>
>
pyCur =
pyCon.Cursor
(
)
>
>
>
lt =
pyCur.ExecuteTuple
(
'
Select
*
from
Country
'
)
>
>
>
lm =
pyCur.ExecuteMap
(
'
Select
*
from
Country
'
)
>
>
>
l =
pyCur.ExecuteListe
(
'
Select
CURRENCY
from
Country
'
)
>
>
>
print
lt[5
]
(
'
Italy
'
, '
Lira
'
)
>
>
>
print
lm[5
]
(
result set row with
COUNTRY =
Italy, CURRENCY =
Lira)
>
>
>
print
lm[5
]['
COUNTRY
'
]
Italy
>
>
>
print
l[5
]
Lira
IV. Programmation sous Delphi▲
Nous allons maintenant à partir de Delphi accéder à l'interface développée en Python.
Assurez-vous tout d'abord que vous avez installé Firebird et PythonForDelphi et que vous avez récupéré les sources du
projet. Ces sources contiennent en plus le fichier FBBase.py et le runtime Python.
Ouvrez ensuite le projet AdminBase.dpr.
Si vous choisissez l'installation complète de Python, vous pouvez effacer le runtime (répertoire kinterbasdb et encodings et les fichiers .pyc et .pyd) ainsi que la dll Python25.dll (la suppression de la dll est obligatoire sinon l'application détectant cette dll ne cherchera le module kinterbasdb que dans ce répertoire (et ne le trouvera donc pas))
IV-A. Connection à la base de données et initialisation des objets▲
Nous n'entrerons pas dans le détail de l'utilisation des composants fournit par PythonForDelphi mais seulement pour ceux qui nous intéressent. Si vous souhaitez approfondir le sujet, vous trouverez des tutoriaux sur le site de téléchargement de la bibliothèque et de nombreuses démos sont disponibles lors de l'installation des composants.
IV-A-1. PythonEngine▲
Ce composant fait le lien avec la machine virtuelle Python. Dans votre programme Python, il ne peut y en avoir qu'un seul en même temps. C'est le seul composant de la barre de composants que nous utiliserons. Sur la fiche, vous voyez ce composant avec une tête de Python nommé PE (nom usuel)
IV-A-2. Initialisation des objets▲
On remarquera dans les uses l'unité VarPyth (ajoutée à la "main"). Cette unité fournit des variables globales d'accès à des objets Python.
procedure
TfrmAdmin.FormCreate(Sender: TObject);
var
PyStrings:TStringList;
begin
Caption:='
Visualisation
d
'
'
une
Base
Firebird
-
Version
'
+Version ;
//
Récupération
du
code
du
module
python
FBBase.py
PyStrings:=TStringList.Create;
PyStrings.LoadFromFile('
FBBase.py
'
);
//
Exécution
du
code
en
mémoire
dans
le
moteur
Python
PE.ExecStrings(PyStrings);
//
Création
d'un
objet
TFBBase
permettant
de
manipuler
la
base
de
données
pyCon:=MainModule.TFBConnection();
PyStrings.Free;
end
;
Une première chose est de mettre en mémoire dans le moteur Python le code Python de l'interface FBBase.py.
Pour cela la fonction PE.ExecStrings(pystr: Strings) permet d'exécuter le code source contenu dans pystr.
Tout objet défini dans pystr est alors directement accessible dans la variable globale MainModule.
MainModule.TFBConnection() appelle le constructeur __init__ de la classe TFBConnection et retourne une instance correspondante.
Pour l'instant, notre instance pyCon est initialisée avec des valeurs par défaut (ceux définis dans la classe Python). Il s'agit donc des
paramètres correspondant à la base de données que l'on a lors de l'installation de Firebird. Par contre, nous ne sommes pas encore
connectés à cette base.
Tout objet Python est déclaré en Delphi en tant que variant.
IV-A-3. Connexion à la base de données▲
procedure
TfrmAdmin.btnConnectClick(Sender: TObject);
var
pyltables,pylchamps:variant;
pyCur:variant;
i:integer
;
begin
//
connection
à
la
base
de
données
avec
les
nouveaux
paramètres
pyCon.host:=ehost.Text;
pyCon.database:=edatabase.Text;
pyCon.user:=euser.text;
pyCon.password:=epassword.Text;
try
pyCon.Connect() ;
...
end
;
On accède aux attributs/fonctions d'une instance Python de la même façon qu'en Delphi.
La première chose est de se connecter à la base avec pyCon.Connect().
En Python, le typage est dynamique; on peut donc associer à un attribut n'importe quel type et le changer à tout moment.
Encore une fois, il faut bien respecter la casse sur l'utilisation des attributs/fonctions de pyCon.
IV-B. Utilisation de requêtes SQL▲
IV-B-1. Exemple 1▲
procedure
TfrmAdmin.btnConnectClick(Sender: TObject);
var
pyltables,pylchamps:variant;
pyCur:variant;
i:integer
;
begin
...
//
Création
d'un
curseur
pyCur:=pyCon.Cursor();
//
On
liste
les
tables
de
la
base
et
on
remplit
un
comboBox
pyltables := pyCur.ListeTable();
comboTable.Clear;
for
i:=0
to
len(pyltables)-1
do
comboTable.items.Add(pyltables.GetItem(i));
comboTable.ItemIndex:=0
;
//
On
liste
les
champs
de
la
table
sélectionnée
et
on
remplit
un
combobox
pylchamps:= pyCur.ListeChamps(comboTable.Text);
comboChamp.Clear;
for
i:=0
to
len(pylchamps)-1
do
comboChamp.items.Add(pylchamps.GetItem(i));
combochamp.ItemIndex:=0
;
btnAfficherTuple.Enabled:=true
;
btnAfficherMap.Enabled:=true
;
pyCur.Close()
except
MessageDlg('
Erreur
:
La
connexion
a
la
base
de
données
n
'
'
a
pu
se
faire
'
, mtError, [mbOk], 0
);
end
;
end
;
procedure
TfrmAdmin.comboTableChange(Sender: TObject);
var
pylchamps:variant;
i:integer
;
pyCur:variant;
begin
pyCur:=pyCon.Cursor();
//
Si
on
sélectionne
une
nouvelle
table,
on
met
à
jour
la
comboBox
des
champs.
pylchamps:= pyCur.ListeChamp(comboTable.Text);
comboChamp.Clear;
for
i:=0
to
len(pylchamps)-1
do
comboChamp.items.Add(pylchamps.GetItem(i));
combochamp.ItemIndex:=0
;
pyCur.Close()
end
;
Voici le premier exemple de l'utilisation d'un objet TFBCursor:
Lorsque vous cliquer sur le bouton "Connecter", le programme remplit les combobox de l'encadré Requête avec le nom des
tables de la base de données et le nom des champs de la table sélectionnée.
Pour cela, on utilise le curseur pyCur et les fonctions vues auparavant ListeTable et ListeChamp.
Tout résultat retourné par une fonction Python sera récupéré dans une variable Delphi de type variant.
Lorsque vous changer la table, la deuxième combobox est immédiatement modifiée pour recevoir les champs correspondants.
Cependant, Delphi ne permet pas d'utiliser la propriété d'index sur un variant si celui-ci n'est pas un vrai tableau de variant,
c'est à dire qu'il ne sera pas possible d'accéder directement à pyltables[0]. En effet, notre variable représente une liste
de string. Ce problème est contourné par l'unité VarPyth qui détecte des noms spéciaux accolés à une variable variant: GetItem,
SetItem, Length, ... Ainsi on accédera à un élément avec la syntaxe pyltables.GetItem(0).
On notera également la fonction global len (équivalent à .Length()) qui permet de connaître la longueur d'une liste
Je vous encourage à parcourir le fichier VarPyth.pas pour de plus amples explications
IV-B-2. Exemple 2▲
Pour afficher le résultat de la requête, nous disposons de 2 bouttons. Le premier utilisera la fonction ExecuteTuple et le deuxième ExecuteMap. Le résultat sera cependant identique.
procedure
TfrmAdmin.btnAfficherTupleClick(Sender: TObject);
var
pyValue,pyChamps:variant;
pyCur:variant;
i,j:integer
;
begin
pyCur:=pyCon.Cursor();
//
On
récupère
le
nom
des
champs
de
la
table
et
on
l'affiche
dans
la
StringGrid
pyChamps:=pyCur.ListeChamps(comboTable.Text);
sgTable.ColCount:=len(pyChamps);
for
j:=0
to
len(pyChamps)-1
do
begin
sgTable.Cells[j,0
]:=pyChamps.GetItem(j);
sgTable.ColWidths[j]:=100
;
end
;
//
On
récupère
toutes
les
valeurs
de
la
table
sélectionnée
avec
tri
selon
le
champs
sélectionné
pyValue:=pyCur.ExecuteTuple('
select
*
from
'
+comboTable.Text+'
order
by
'
+combochamp.Text);
sgTable.RowCount:=len(pyValue)+1
;
for
i:=0
to
len(pyValue)-1
do
for
j:=0
to
len(pyValue.GetItem(i))-1
do
sgTable.Cells[j,i+1
]:=pyValue.GetItem(i).GetItem(j);
pyCur.Close()
end
;
Dans ce deuxième exemple, on va afficher une table complète. Pour cela on exécute la requête pyCur.ExecuteTuple('select * from '+comboTable.Text+' order by '+combochamp.Text); qui nous retourne une liste de tuples (équivalent à une liste de listes). Pour accéder à un élément, il suffira de doubler l'utilisation du GetItem: pyValue.GetItem(i).GetItem(j)
procedure
TfrmAdmin.btnAfficherMapClick(Sender: TObject);
var
pyValue,pyChamps:variant;
pyCur:variant;
i,j:integer
;
begin
pyCur:=pyCon.Cursor();
//
On
récupère
le
nom
des
champs
de
la
table
et
on
l'affiche
dans
la
StringGrid
pyChamps:=pyCur.ListeChamp(comboTable.Text);
sgTable.ColCount:=len(pyChamps);
for
j:=0
to
len(pyChamps)-1
do
begin
sgTable.Cells[j,0
]:=pyChamps.GetItem(j);
sgTable.ColWidths[j]:=100
;
end
;
//
On
récupère
toutes
les
valeurs
de
la
table
sélectionnée
avec
tri
selon
le
champs
sélectionné
pyValue:=pyCur.ExecuteMap('
select
*
from
'
+comboTable.Text+'
order
by
'
+combochamp.Text);
sgTable.RowCount:=len(pyValue)+1
;
for
i:=0
to
len(pyValue)-1
do
for
j:=0
to
len(pyValue.GetItem(i))-1
do
sgTable.Cells[j,i+1
]:=pyValue.GetItem(i).GetItem(pyChamps.GetItem(j));
pyCur.Close()
end
;
Cette fonction est identique à la précédente exceptée les lignes pyValue:=pyCur.ExecuteMap(...) et sgTable.Cells[j,i+1]:=pyValue.GetItem(i).GetItem(pyChamps.GetItem(j));. Pour accéder à un élément, on n'utilise plus un index numérique mais le nom d'un champ (pour conserver la généricité de la fonction, le nom du champ se trouve donc dans pyChamps.GetItem(j)).
V. Pour aller plus loin▲
Ce tutoriel et les sources fournies ont été conçus pour fonctionner avec les bases Firebird. Cependant
on a vu que d'autres bibliothèques Python pour l'accès à d'autres bases de données respectent le standard DBAPI. Il
est donc envisageable d'utiliser la même interface Python pour d'autres bases de données.
Je propose donc une nouvelle interface pyBase.py qui fonctionnera avec les bases de données suivantes:
Firebird, MySQL
V-A. Interface pyBase.py▲
Vous pouvez télécharger cette interface ici. Le nom des classes a un peu changé
afin d'avoir une nomenclature générale. Un paramètre supplémentaire name a été ajouté pour la construction de l'instance
TpyConnection qui vous permettra de de sélectionner le type de la base de données utilisées.
V-B. Déploiement de vos applications▲
Outre votre exécutable créé sous Delphi et les fichiers dépendants, il vous faudra comme précédemment copier ou installer d'autres fichiers.
V-B-1. Interface pyBase.py▲
Il vous suffit simplement de copier ce fichier à la racine du répertoire de votre application
V-B-2. Dépendances Python▲
Cette fois-ci, je n'ai pas préparé de runtime. Vous ne serez pas obligé d'installer toutes les librairies, mais juste celles
correspondantes aux bases de données souhaitées. Vous trouverez tous les liens nécessaires ici.
A l'heure actuelle, il n'existe pas d'installateur pour MySQLdb compatible Python 2.5 n'étant pas disponible, vous devrez vous rabattre sur des versions
compatibles 2.4 (y compris pour toutes les autres bibliothèques)
- Python 2.4.4 (pour toutes les BDDs)
- kinterbasdb 3.2.0 (Firebird)
- MySQLdb 1.2.1 (MySQL)
V-B-3. Ajout de nouvelles bases de données▲
Si vous voulez utilisez d'autres BDDs, il vous faudra tout d'abord modifier le fichier pyBase.py:
- En premier lieu, ajout de l'importation du module correspondant au début du fichier
- Modification de la fonction Connect de la classe TpyConnection
Pour le déploiement, comme la construction du runtime est assez compliqué (j'y travaille pour essayer de le
rendre plus simple), je vous conseille d'opter pour l'installation complète.
Voici une liste des modules à récupérer si vous souhaitez tester d'autres bases de données. Je n'ai pas testé ces modules mais
vous devriez trouver sur les sites la documentation nécessaire.
BDD | Module | Lien |
---|---|---|
Firebird/Interbase | kinterbasdb | http://kinterbasdb.sourceforge.net/ |
MySQL | MySQLdb | http://sourceforge.net/projects/mysql-python |
ODBC | mxODBC | http://www.egenix.com/ |
Oracle | DCOracle2 | http://www.computronix.com/utilities.shtml |
MSSQL Server | mssqldb | http://www.object-craft.com.au/projects/mssql/ |
DB2 | DB2 | ftp://people.linuxkorea.co.kr/pub/DB2/ |
PostGreSQL | psycopg | http://initd.org/projects/psycopg1 |
SAP DB | sapdbapi | http://www.sapdb.org/sapdbapi.html |
Sybase | Sybase | http://www.object-craft.com.au/projects/sybase/ |
VI. Téléchargement▲
Voici le récapitulatif de ce que vous pouvez télécharger:
Fichier | Description | Taille | Mode FTP | Mode HTTP de secours |
---|---|---|---|---|
FBBase.py | Interface Python/Firebird | 7 Ko | FBBase.py | FBBase.py |
pyBase.py | Interface Python/Firebird/MySQL | 7 Ko | pyBase.py | pyBase.py |
FBAdminBase0.2.1.zip | Source + exécutable de l'application sans les dépendances Python | 307 Ko | FBAdminBase0.2.1.zip | FBAdminBase0.2.1.zip |
FBRuntimePython.zip | Runtime Python/Firebird | 1.63 Mo | FBRuntimePython.zip | FBRuntimePython.zip |
FBAdminBase0.2.1-FBRuntimePython-FBBase.py.zip | Application complète + Runtime Python/Firebird + FBBase | 1.94 Mo | FBAdminBase0.2.1-FBRuntimePython-FBBase.py.zip | FBAdminBase0.2.1-FBRuntimePython-FBBase.py.zip |
VII. Conclusion▲
L'accès aux bases de données sous une version personnelle de Delphi se fait de manière très simple grâce
à l'utilisation des composants PythonForDelphi. De plus aucune connaissance en Python n'est nécessaire, d'où
l'intérêt pour les Delphiistes.