Other organisations may provide you with half baked solutions, but we cover the whole kitchen.
The dbBrowser application is shipped as a sample with PythonCard. Its purpose is to allow you to easily browse data stored in a relational database or similar structured store.
The application is designed to demonstrate useful techniques with the PythonCard toolkit, in particular the dynamic creation and placement of widgets and, in dbBrowser2, the use of a simple wxGrid
From its inception the application was designed to be as modular as possible, to allow it to be used with as many databases as possible. In this modular approach all that is required to support a different data store is to provide a browsing module which supports a fairly simple interface.
To provide an adaptor for a new database create a new module which should go in the same directory as the rest of the application code. The convention for naming these modules is <em>database name</em>Browse.py, (e.g.
mySQLBrowse.py). The name is not crucial, but the module must contain a class called
This class must support the following methods;
The connection parameter is a dictionary. This dictionary can contain either the keys
The first variation is for traditional relational databases that support named user access such as
Oracle, MySQL and PostgreSQL. The second option is for the more simple types of data store like
SQLite which just allow us to specify a file which contains our data.
The purpose of this method is to establish our connection to the database and, if successful, to
establish two attributes (
_cursor) which are used by the other methods.
This method should return a list of all of the available tables in the database. Where the database
supports secured access this list should only contain those tables to which the current user has access.
In the Oracle module, for instance, this is achieved by querying
user_tables rather than
The returned list probably doesn't want to include system or data dictionary tables. In the MySQL
module, for instance, the system tables (whose names are stored in the
are explicitly exluded.
This method returns a list containing the details of all of the columns in
Each item in the list is a tuple detailing a single column. These tuples contain (in order), the
column's name, the data type, the precision (or more usually the maximum number of characters or
digits the column can contain), whether the column is nullable ('YES' or 'NO'), whether it forms
part of a key ('PRI' or 'UNI'), lastly the default value, if one is defined.
This method must return a string which contains a valid query string for
It is primarily used by the 'get' functions and isn't necessary for dbBrowser to function.
In those modules which use Python DB-API compliant modules it should be possible to take
this string and pass it to the
execute method of a cursor object directly.
This method should return a single row from
tableName. As per the Python DB-API this
will be a sequence (either a tuple or a list depending on how the database module implements
This method should return all of the rows from
tableName. As per the Python DB-API
this will be a sequence of sequences. This method will use the
fetchall method as opposed
getRow's use of
Possible improvements to the code that I've spotted whilst writing this documentation are;
Normalise the keys used in the connection dictionary. We should have a consistent database name, at present it uses
Raise an exception when the
__init__ method fails to establish a connection to our selected database. At the moment the calling module checks to see if
self._cursor contains a valid cursor object.
The tuples returned from the
getColumns method should be more generic. At the moment every backend attempts to mimic the MySQL
getRow method should be turned into an iterator that when called repeatedly will return sequential rows. At the moment it will always return the first row that the database supplies.
getRow method could be moved into a super class and then only overriden for non RDBMS backends
getRows method could be moved into a super class and then only overriden for non RDBMS backends
Last updated: 2nd September, 2003. Author: Andy Todd <firstname.lastname@example.org>