für einen Dateikonverter benötigte ich ein Werkzeug, dass mir Datenbank - Ids generieren kann. Diese Ids müssen relativ flexibel sein, da in der Datenbank eine Vielzahl von unterschiedlichen Primärschlüsseln vorkommen können. Der häufigste Fall sind Primärschlüssel vom Typ Varchar, so dass die Datenbank keine eindeutige Id selber vergeben kann. Es gibt aber auch tinyint Primärschlüssel ohne Autoincrement. Ausserdem profitiert die Anwendung (das Programm, das die Datenbank nutzt) von sequentiellen Ids.
Das Werkzeug muss also die Ids generieren können, nachsehen, ob die Id schon in der Tabelle existiert und in einem in einem bestimmten Format zurückgeben. Zuerst hatte ich eine Funktion, die das Generieren der Ids übernahm, allerdings war das Implementieren der Sequenz der Ids nicht so einfach zu lösen. Deshalb habe ich eine Iterator Klasse geschrieben, die diese Problematik löst.
Das übergebene Connection - Objekt ist eine Pyodbc - Connection, die ich um ein Listenattribut zur Speicherung der bereits generierten Ids erweitert habe.
Code: Alles auswählen
class IDGenerator(object):
"""Generate a unique id in the given table for the given column
with given length. Tries to generete sequential id numbers"""
def __init__(self, connection, table_name, col_name, length, type=int):
self.connection = connection
self.length = length
self.type = type
self.max_tries = 20
self.num_tries = 0
self.id = None
self.last_id = None
self.raw_sql = 'SELECT "{0}" FROM "{1}" WHERE "{0}" = ?'
self.sql = self.raw_sql.format(col_name, table_name)
def __iter__(self):
return self
def generate(self):
"""Generate a random id"""
return random.randrange(1, pow(10, self.length)-1)
def is_free(self, id):
"""Test if a id is still available in the table's column"""
if id not in self.connection.generated_ids:
cursor = self.connection.cursor()
row = cursor.execute(self.sql, str(id)).fetchone()
if row:
self.max_tries += 1
return False
return True
def next(self):
while self.num_tries <= self.max_tries:
# if there's no id generate one else increment existing by one
if not self.id:
self.id = self.generate()
else:
self.id += 1
# add the generated id to the connection's list of generated ids
# in order to prevent unecessary checks against the database
self.connection.generated_ids.append(id)
# if id is free, return it or generate a new one
if self.is_free(self.id):
return self.type(self.id)
else:
self.id = self.generate()
else:
raise StopIteration
und so wird's genutzt:
Code: Alles auswählen
my_generator = IDGenerator(connection, 'Flaechennutzung', 'FNr', 19, str)
my_id = next(my_generator)
Frank