erstes Kennenlernen mit SQLAlchemy sehr holprig...

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
sedi
User
Beiträge: 104
Registriert: Sonntag 9. Dezember 2007, 19:22

Hilfeeee,

habe ein größeres Projekt vor der Brust und habe lange über die Speicherung der Daten nachgedacht. Nach langem (sehr langem) Hin und Her habe ich mich zu SQLAlchemy mit sqlite entschlossen. Als absoluter ORM-Neuling wollte ich erst mal die ersten Gehversuche wagen:

Habe versucht den gesamten SQL-Alchemy-Code in einer extra Klasse zu kapseln und im Testlauf probiert Daten in die Datenbank einzutragen. Die Datenbank zu erstellen war sofort durchführbar, aber ich schaffe es nicht Daten einzutragen.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from sqlalchemy import Table, Column, create_engine, MetaData, Integer, Unicode
from sqlalchemy.orm import mapper, sessionmaker

class cPerson(object):
   def __init__(self, sNachname, sVorname, dGebdat):
      self.lsVorname=sVorname; self.lsNachname=sNachname; self.ldGebdat=dGebdat
   def __repr__(self):
      return u"<Person('%s','%s','%s')>", (self.lsNachname, self.lsVorname, self.ldGebdat)
   def __str__(self):
      txt = u"\tNachname: " + unicode(self.lsNachname)
      txt += u"\n\tVorname: " + unicode(self.lsVorname)
      txt += u"\n\tGeburtsdatum: " + unicode(self.ldGebdat)
      return txt

class cSQLAlchemy(object):
   def __init__(self, sDriver="", sDBFile=""):
      '''initialisiert sqlAlchemy und öffnet bzw erzeugt ggf. die DB'''
      #Vorbereitung verschiedener Variablen
      self.lDriver=None; self.lDBFile=None; self.lSession=None
      self.lSessionobject=None; self.lEngine=None; self.lPersonMapper=None
      #DB - Variablen
      self.tblPerson=None; self.tblSchueler=None; self.tblLehrer=None
      #setzen von Treiber und File
      self.lDriver=sDriver; self.lDBFile=sDBFile
      #Testen der Argumente (default=sqlite)
      if self.lDriver==None: self.lDriver=='sqlite://'
      else:
         #sind die drei letzten Zeichen ://, wenn nicht dann anhängen
         if self.lDriver[len(self.lDriver)-3:len(self.lDriver)]!='://': 
            self.lDriver+= '://'
      # starten der engine
      if self.lDriver=='sqlite://':
         if self.lDBFile==None: self.lDBFile='/:memory:'
         from sqlalchemy.databases.sqlite import SQLiteDialect
         try:
            #print "\nDriver: " + self.lDriver + "\nFile:   " + self.lDBFile + "\n\n"
            #print "Komplett: " + self.lDriver + '/' + self.lDBFile + "\n"
            self.lEngine = create_engine(self.lDriver + '/' + self.lDBFile, echo=True)
         except:
            raise RuntimeError, "Couldn\'t set up engine!"
      else:
         raise RuntimeError, "Unknown database driver!"
      #starten der Sessionobjekt
      try:
         self.lSessionobject=sessionmaker(bind=self.lEngine, autoflush=True, transactional=True)
      except:
         pass
   def __repr__(self):
      return u"<cSQLAlchemy (driver=" + unicode(self.lDriver) + u", database=" + unicode(self.lDBFile) + u")>"
   def getEngine(self):
      return self.lEngine
   def getSessionobject(self):
      return self.lSessionobject
   #Person------------------------------------------------------------------------
   def createPersonentabelle(self):
      metadata=MetaData()
      self.tblPerson = Table('Personen', metadata,
         Column('PersonID', Integer, primary_key=True),
         Column('Nachname', Unicode(40), nullable=False),
         Column('Vorname', Unicode(40)),
         Column('Geburtsdatum', Unicode(10))
      )
      metadata.create_all(self.getEngine())
      self.lPersonMapper = mapper(cPerson, self.tblPerson)
   def saveNewPerson(self, person):
      self.lSession=self.lSessionobject()
      self.lSession.save(person)
      self.lSession.commit()

# =========================================================================================
# TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST
if __name__=='__main__':
   person=cPerson(u"Meier", u"Hans", u"12.11.1933")
   db = cSQLAlchemy("sqlite", "/home/sej/bin/scripts/python/modules/sis/data/sis.db")
   db.createPersonentabelle()
   db.saveNewPerson(person)

Die Fehlermeldung (Traceback):

Traceback (most recent call last):
File "/home/sej/bin/scripts/python/modules/sql.py", line 79, in <module>
db.saveNewPerson(person)
File "/home/sej/bin/scripts/python/modules/sql.py", line 71, in saveNewPerson
self.lSession.commit()
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/session.py", line 544, in commit
self.transaction.commit()
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/session.py", line 250, in commit
self._prepare_impl()
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/session.py", line 234, in _prepare_impl
self.session.flush()
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/session.py", line 764, in flush
self.uow.flush(self, objects)
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/unitofwork.py", line 215, in flush
flush_context.execute()
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/unitofwork.py", line 437, in execute
UOWExecutor().execute(self, tasks)
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/unitofwork.py", line 927, in execute
self.execute_save_steps(trans, task)
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/unitofwork.py", line 942, in execute_save_steps
self.save_objects(trans, task)
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/unitofwork.py", line 933, in save_objects
task.mapper._save_obj(task.polymorphic_tosave_objects, trans)
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/mapper.py", line 972, in _save_obj
instance_key = mapper._identity_key_from_state(state)
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/mapper.py", line 881, in _identity_key_from_state
return self.identity_key_from_primary_key(self._primary_key_from_state(state))
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/mapper.py", line 891, in _primary_key_from_state
return [self._get_state_attr_by_column(state, column) for column in self.primary_key]
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/mapper.py", line 910, in _get_state_attr_by_column
return self._get_col_to_prop(column).getattr(state, column)
File "/usr/local/lib/python2.5/site-packages/SQLAlchemy-0.4.3-py2.5.egg/sqlalchemy/orm/properties.py", line 66, in getattr
return getattr(state.class_, self.key).impl.get(state)
AttributeError: 'ColumnProperty' object has no attribute 'key'

Vielen Dank im Voraus...
CU sedi
----------------------------------------------------------
Python 3.5; Python 3.6
LinuxMint18
lunar

Mal ganz grundsätzlich: Halte dich an PEP 8 und lass bitte ab von der Verwendung der Ungarischen Notation!

Zum programmatischen Erzeugen der Datenbank-URL nimmst du besser die Klasse sqlalchemy.engine.url.URL, anstatt auf String-Manipulationen zurückzugreifen.

Zum eigentlichen Problem: Die Instanzvariablen der Klasse cPerson haben andere Namen als die in createPersonentabelle definierten Spalten.

So heißt Nachname[i/] in der Klasse lsNachname. SQLAlchemy findet also kein Attribut Nachname in der Klasse und keine key Attribute in den Spalten, kann also das Attribut keine Spalte zuordnen.

Du solltest erstmal das SQL-Alchemy-Tutorial durcharbeiten und dringenst deinen Codestil verbessern. Ungarische Notation ist selbst bei statisch typisierten Sprachen Mist, bei Python aber komplett unsinnig. Die Tatsache, dass du sie verwendest, lässt auch darauf schließen, dass du von Python's Objektmodell noch nicht allzu viel Ahnung hast.
sedi
User
Beiträge: 104
Registriert: Sonntag 9. Dezember 2007, 19:22

hallo, danke für den hinweis (u danke für die markigen worte),

aber es stimmt, bin tatsächlich noch nich so lange bei python - habe mal schnell (quickndirty) zu python rüber geschaut und bin hängen geblieben. :wink: .
CU sedi
----------------------------------------------------------
Python 3.5; Python 3.6
LinuxMint18
Antworten