2009-05-13 12 views
30

scheint Dies kann eher argumentative, aber ich ging gerade durch SQLAlchemy des ORM tutorial und endete mit dem folgenden Code auf:SQLAlchemy ist verschachtelt?

from sqlalchemy import create_engine 
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 

engine = create_engine('sqlite:///:memory:', echo=True) 

metadata = MetaData() 
users_table = Table('users', metadata, 
    Column('id', Integer, primary_key=True), 
    Column('name', String), 
    Column('fullname', String), 
    Column('password', String) 
) 

metadata.create_all(engine) 

Base = declarative_base() 
class User(Base): 
    __tablename__ = 'users' 

    id = Column(Integer, primary_key=True) 
    name = Column(String) 
    fullname = Column(String) 
    password = Column(String) 

    def __init__(self, name, fullname, password): 
     self.name = name 
     self.fullname = fullname 
     self.password = password 

    def __repr__(self): 
     return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password) 

users_table = User.__table__ 
metadata = Base.metadata 

Session = sessionmaker(bind=engine) 
Session = sessionmaker() 
Session.configure(bind=engine) # once engine is available 
session = Session() 

# actually using the ORM isn't too bad.. 
ed_user = User('ed', 'Ed Jones', 'edspassword') 
session.add(ed_user) 

our_user = session.query(User).filter_by(name='ed').first() 
print our_user 

session.add_all([ 
    User('wendy', 'Wendy Williams', 'foobar'), 
    User('mary', 'Mary Contrary', 'xxg527'), 
    User('fred', 'Fred Flinstone', 'blah')]) 

ed_user.password = 'f8s7ccs' 

print session.dirty 
print session.new 
session.commit() 

for instance in session.query(User).order_by(User.id): 
    print instance.name, instance.fullname 

for name, fullname in session.query(User.name, User.fullname): 
    print name, fullname 

Dieses für effektiv einen Hallo Welt Tisch unglaublich kompliziert scheint, vor allem im Vergleich zu dem in etwa ähnlich SQLObject Code:

from sqlobject import SQLObject, StringCol, sqlhub, connectionForURI 

sqlhub.processConnection = connectionForURI('sqlite:/:memory:') 

class Person(SQLObject): 
    fname = StringCol() 
    mi = StringCol(length=1, default=None) 
    lname = StringCol() 

Person.createTable() 

p = Person(fname="John", lname="Doe") 
p.mi = 'Q' 
p2 = Person.get(1) 
print p2 
print p2 is p 

ich verstehe SQLAlchemy „mächtiger“ ist, aber diese Macht scheint zu einem Preis zu kommen, oder bin ich etwas fehlt?

+8

Strom kommt auf Kosten? Was sagst du? –

+12

Die Leistung von SQLAlchemy geht auf Kosten der Einfachheit der Nutzung? – dbr

+3

Versuchen Sie Elixir wie unten erwähnt, Ihre Hello World wird SQLObject sehr ähnlich sein, und Sie werden weiterhin auf die SQLAlchemy-Ebene zugreifen können. Ich habe SQLObject benutzt und war frustriert von seinen Einschränkungen, und ich bin bisher sehr zufrieden mit Elixir (es fehlt ein wenig Dokumentation und Unterstützung, aber die Benutzerbasis scheint leider begrenzt). –

Antwort

85

Nun, es gibt eine Sache, die Sie vermissen: Das Tutorial, das Sie erwähnen, "baut" kein vollständiges Beispiel, die verschiedenen Codeschnipsel sind nicht dazu gedacht, in einer Quelldatei verkettet zu werden. Sie beschreiben vielmehr die unterschiedlichen Verwendungsmöglichkeiten der Bibliothek. Es ist nicht nötig, das gleiche immer und immer wieder zu versuchen.

die tatsächlich betriebener-the-orm Teil aus Ihrem Beispiel Auslassen könnte der Code wie folgt aussehen:

from sqlalchemy import * 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker, scoped_session 

engine = create_engine('sqlite:///:memory:', echo=True) 
Base = declarative_base(bind=engine) 
Session = scoped_session(sessionmaker(engine)) 

class User(Base): 
    __tablename__ = 'users' 

    id = Column(Integer, primary_key=True) 
    name = Column(String) 
    fullname = Column(String) 
    password = Column(String) 

Base.metadata.create_all() 

Die „deklarative“ Erweiterung kümmert sich um die Tabelle zu definieren und es zu Ihrer Klasse zuordnen , so dass Sie die users_table nicht selbst deklarieren müssen. Die Benutzerklasse ermöglicht auch die Instanziierung mit Schlüsselwortargumenten wie User(name="foo") (aber nicht mit Positionsargumenten). Ich habe auch die Verwendung von scoped_session hinzugefügt, was bedeutet, dass Sie Session direkt verwenden können, ohne es tatsächlich instanziieren zu müssen (es wird eine neue Sitzung instanziieren, wenn nicht bereits eine im aktuellen Thread vorhanden ist, oder die vorhandene wiederverwenden)

+2

Das sieht ein bisschen vernünftiger aus als der Code, mit dem ich endete. Vielen Dank! – dbr

+1

Ich bin sehr zögerlich über 'scoped_session' für vieles von allem; Wenn Sie nicht wissen, warum Sie lokalen Thread-Speicher benötigen, sollten Sie die Sitzung explizit instanziieren und bei Bedarf weitergeben. – SingleNegationElimination

+1

@TokenMacGuy Ich stimme überhaupt nicht zu. 'scoped_session' nimmt das Rätselraten und unnötige Argument, dass keine Sitzungen mehr verwendet werden. Sie definieren einfach Ihre Klasse "scoped_session" am Anfang und instanziieren sie dort, wo Sie Zugriff auf die Sitzung benötigen, und das System erledigt den Rest. Ich habe festgestellt, dass es extrem praktisch für alle Web-Apps ist, die ich geschrieben habe. – CoreDumpError

0

Sie sagen "verschachtelte" .... jemand anderes könnte sagen "flexibel". Manchmal brauchst du es manchmal nicht. Ist es nicht großartig, dass du die Wahl hast?

+0

Sicher, aber ich sage "verschachtelt", weil es dich zwingt, eine Menge seiner Funktionen zu verwenden, um grundlegende Dinge zu tun. Flexibilität ist großartig, aber nicht, wenn es fünf Zeilen von Importen gibt, nur um anzufangen! – dbr

1

Nun, SQLAlchemy ist in verschiedene Teile unterteilt, der Hauptkernteil behandelt einfach die DB und transformiert Ihre Python-gebauten Abfragen in die entsprechende SQL-Sprache für die zugrunde liegende DB. Dann gibt es die Unterstützung für Sitzungen, die ORM und die neue deklarative Syntax.

Sieht aus wie SQLObject (ich kann nicht sicher sagen, habe es seit vielen Jahren nicht mehr benutzt, und selbst dann nur einmal) überspringt das meiste davon und macht den ORM-Teil sofort. Dies macht es oft einfacher für einfache Daten (die Sie in den meisten Fällen erhalten können), aber SQLAlchemy ermöglicht komplexere db-Layouts, und gehen Sie mit der db herunter und schmutzig, wenn Sie es wirklich brauchen.

+0

SQLObject scheint fortgeschrittenere Dinge zu unterstützen, wie Eins-zu-Viele/Viele-zu-Eins/Viele-zu-Viele-Beziehungen (die jedes Datenbanklayout abdecken, das ich gesehen habe) und Transaktionen. – dbr

10

Die von Ihnen angegebenen Codebeispiele sind keine Äpfel zu Äpfeln. Die SQLAlchemy Version könnte ein wenig abgespeckt werden:

from sqlalchemy import create_engine 
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 

engine = create_engine('sqlite:///:memory:', echo=True) 
Base = declarative_base() 

class User(Base): 
    __tablename__ = 'users' 

    id = Column('id', Integer, primary_key=True) 
    name = Column('name', String) 
    fullname = Column('fullname', String) 
    password = Column('password', String) 

    def __repr__(self): 
     return "" % (self.name, self.fullname, self.password) 

Base.metadata.create_all(engine) 

Session = sessionmaker(bind=engine) 
session = Session() 

# actually using the ORM isn't too bad.. 
ed_user = User(name='ed', fullname='Ed Jones', password='edspassword') 
session.add(ed_user) 

our_user = session.query(User).filter_by(name='ed').first() 

session.add_all([ 
    User(name='wendy', fullname='Wendy Williams', password='foobar'), 
    User(name='mary', fullname='Mary Contrary', password='xxg527'), 
    User(name='fred', fullname='Fred Flinstone', password='blah')]) 

ed_user.password = 'f8s7ccs' 

session.flush() 

for instance in session.query(User).order_by(User.id): 
    print instance.name, instance.fullname 

for name, fullname in session.query(User.name, User.fullname): 
    print name, fullname 

Sie auch Elixir mehr wie SQLObject finden könnten (aber da ich auch nicht verwendet haben, das ist nur eine Vermutung).

Ich habe SQLObject überhaupt nicht benutzt, ich kann nicht sagen, was genau SA besser macht. Aber ich habe großartige Erfahrungen mit SA gemacht, besonders im Umgang mit komplizierten, realen, alten Schemata. Es macht gute Arbeit mit guten SQL-Abfragen standardmäßig und hat viele Möglichkeiten, sie zu tunen.

Ich habe SQLAlchemy Autor elevator pitch gefunden, um in der Praxis ziemlich gut zu halten.

1

Nachdem ich SQLObject verwendet habe (und nur über SQLAlchemy gelesen habe), kann ich sagen, dass eine der Stärken von SQLObject die Leichtigkeit und Einfachheit ist, mit der man Dinge erledigen kann.Darüber hinaus bietet die E-Mail-Gruppe (https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss) hervorragende Unterstützung, die Ihnen schnell Antworten liefert.

1

Quick ORM Versuchen Sie, es ist noch einfacher:

from quick_orm.core import Database 
from sqlalchemy import Column, String 

class User(object): 
    __metaclass__ = Database.DefaultMeta 
    name = Column(String(30)) 

if __name__ == '__main__': 
    database = Database('sqlite://') 
    database.create_tables() 

    user = User(name = 'Hello World') 
    database.session.add_then_commit(user) 

    user = database.session.query(User).get(1) 
    print 'My name is', user.name 

Quick ORM wird auf SQLAlchemy gebaut, so könnten wir sagen, dass SQLAlchemy als SQLObject könnte so einfach sein.

+0

Es tut mir leid, dass quick_orm nicht mehr gepflegt wird. –