SQLAlchemy + Threads

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

Hi,

Ich suche hier Rat zu einem "hack" von leuten die Erfahrung mit SQLAlchemy in Anwendungen mit Threads haben.

Und zwar geht es mir um die Frage, wie man die Sessions pro thread erstellt. Soweit ich das verstanden habe, wird für jeden Thread eine Session mit der methode scoped_session(...) erzeugt und dann in einem object des typs threading.local abgelegt, richtig?
also zB so:

Code: Alles auswählen

from sqlalchemy.orm import scoped_session, sessionmaker
from threading import local

# framework.thread_data = local()

def beim_starten_eines_threads():
    framework.thread_data.session = scoped_session(sessionmaker(...))
Aber ich ich will nicht jedes mal framework.thread_data.session benutzen müssen, um auf die db zuzugreifen. scoped_session macht nichts weiter als ein objekt der Klasse ScopedSession zu erzeugen. Ist der folgende "hack" nicht viel genialer?

Code: Alles auswählen

from threading import local
from sqlalchemy.orm.scoping import ScopedSession

class LocalSession(local, ScopedSession):
    def __init__(self, session_factory, scopefunc=None):
        ScopedSession.__init__(self,session_factory, scopefunc=scopefunc)

def beim_starten_eines_threads():
    db =  LocalSession(sessionmaker(...))
Hat doch den selben effekt, nur dass das object jetzt nur noch db heißt. Habe ich da einen haken übersehen? Ist die varibale jetzt vielleicht nicht mehr überall im webframework "erreichbar", wo sie vorher erreichbar war?

Jan
lunar

Ich denke, du hast nicht verstanden, wie scoped_session funktioniert. Man erzeugt nicht pro Thread eine scoped_session, sondern man erzeugt die scoped_session genau einmal global. Diese globale Session weiß dann automatisch, in welchen Thread sie sich befindet.
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

lunar hat geschrieben:Ich denke, du hast nicht verstanden, wie scoped_session funktioniert. Man erzeugt nicht pro Thread eine scoped_session, sondern man erzeugt die scoped_session genau einmal global. Diese globale Session weiß dann automatisch, in welchen Thread sie sich befindet.
Hmm... Bei web.py wird das objekt auf web.ctx abgelegt. Habe ich die ctx variable nicht verstanden, oder hat web.py scoped_session nicht verstanden?
lunar

Mit web.py kenne ich mich nicht aus ...

Btw, bist du sicher, dass du das verwenden möchtest? Man sagt davon, es wäre mies geschrieben und eigentlich ziemlich kaputt ... zu den verbreiteten Frameworks gehört es auch nicht wirklich.
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

lunar hat geschrieben:Mit web.py kenne ich mich nicht aus ...

Btw, bist du sicher, dass du das verwenden möchtest? Man sagt davon, es wäre mies geschrieben und eigentlich ziemlich kaputt ... zu den verbreiteten Frameworks gehört es auch nicht wirklich.
Ähnliches hat mir gerade auch Leonidas mitgeteilt. Ich suche ein Framwork...
... in welchem ich SQLAlchemy, Jinja2 und memcache benutzen kann
... welches nicht davon ausgeht, dass ich bestimmte Features benutze, welche ich nicht benutzen will (Bsp. Jango ORM)
... welches die überflüssige arbeit möglichst reduziert
.. welches gutes URL mapping besitzt, sodass ich mein Projekt in Pakete unterteilen kann
... welches stabil und akzeptabel performant ist

Gibts da neben Web.py noch ein framework, welches diese anforderung erfüllt?
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Das klingt nicht wirklich als ob du ein Framework suchst. Schon mal einen Blick auf Werkzeug geworfen?
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

DasIch hat geschrieben:Das klingt nicht wirklich als ob du ein Framework suchst. Schon mal einen Blick auf Werkzeug geworfen?
Ja, aber nicht sehr tiefgehend, da ich schon ziemlich bald das gefühl hatte, dass man bei Werkzeug zu viel selbst machen muss.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Jan.O hat geschrieben:Ich suche ein Framwork...
... in welchem ich SQLAlchemy, Jinja2 und memcache benutzen kann
... welches nicht davon ausgeht, dass ich bestimmte Features benutze, welche ich nicht benutzen will (Bsp. Jango ORM)
... welches die überflüssige arbeit möglichst reduziert
.. welches gutes URL mapping besitzt, sodass ich mein Projekt in Pakete unterteilen kann
... welches stabil und akzeptabel performant ist
Hallo Jan.O!

Das sind fast genau die Gründe, weshalb ich CherryPy für mich ausgesucht habe. Und ich wurde nicht enttäuscht. CherryPy ist wirklich genial einfach -- hält aber trotzdem die unangenehme Arbeit von mir ab.

- http://cherrypy.org/
- http://halvar.at/python/cherrypy_cheetah/

Probiere es einfach mal aus. Du brauchst für dieses Beispiel CherryPy und Cheetah.
CherryPy: http://cherrypy.org
Cheetah für Python 2.5: http://www.cheetahtemplate.org/
Cheetah für Python 2.6: http://rtyler.github.com/cheetah/

Code: Alles auswählen

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

import cherrypy
from Cheetah.Template import Template

# Das hier steht normalerweise in eigenen Vorlagendateien
INDEX_TEMPLATE = """<html>
<head></head>
<body>
  <form action="showformdata">
    <p>Vorname: <input type="text" name="vorname" /></p>
    <p>Nachname: <input type="text" name="nachname" /></p>
    <p><input type="submit" value="anzeigen" /></p>
  </form>
</body>
</html>
"""

# Das hier steht normalerweise in eigenen Vorlagendateien
SHOWFORMDATA_TEMPLATE = """<html>
<head></head>
<body>
  <p>Vorname: $vorname</p>
  <p>Nachname: $nachname</p>
</body>
</html>
"""


class Root(object):
    
    def index(self, *args, **kwargs):
        template = Template(INDEX_TEMPLATE)
        return str(template)
    index.exposed = True
    
    
    def showformdata(self, vorname = "", nachname = ""):
        template = Template(SHOWFORMDATA_TEMPLATE)
        template.vorname = vorname
        template.nachname = nachname
        return str(template)
    showformdata.exposed = True


def main():
    cherrypy.quickstart(Root())


if __name__ == "__main__":
    main()
mfg
Gerold
:-)
Zuletzt geändert von gerold am Montag 20. April 2009, 21:34, insgesamt 2-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Naja, was muss man bei Werkzeug selbst machen? Man muss sich einmal ein funktionierendes System/einen Aufbau zusammenbauen, das in seiner App umsetzen und dann kann man damit loslegen. Der Vorteil davon ist: du bist sehr frei und kannst genau das machen, was und wie du willst. Ich verwende Werkzeug mit Jinja und SQLAlchemy (letzteres erst seit kurzem) und komme perfekt damit klar. Performancetechnisch habe ich noch keine Vergleiche gemacht - jemand anders vllt. mehr Infos dazu?
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

gerold hat geschrieben:CherryPy ist wirklich genial einfach -- hält aber trotzdem die unangenehme Arbeit von mir ab.
Es gibt nur einen Grund warum ich CHerrpy in diesem fall nicht einsetzen möchte: weil man an die objektorientierte URL-Bildung gebunden ist.
Folgender fiktiver Navigationsablauf wäre mich Cherrypy nicht möglich

http://www.example.com/users/
http://www.example.com/users/Peter/
http://www.example.com/users/Peter/images/
http://www.example.com/users/Peter/images/124/
http://www.example.com/users/Peter/images/124/comment/

Ich glaube man kann irgendwie einen eigenen URL-Mapper in cherrypy reinprogrammieren. Noch ein Link. Damit werde ich mich aber erst morgen beschäftigen. Gute Nacht @all.

Jan
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Jan.O hat geschrieben:Ich glaube man kann irgendwie einen eigenen URL-Mapper in cherrypy reinprogrammieren.
Hallo Jan.O!

Nicht "reinprogrammieren", sondern schlicht "nutzen". :-)
Ideal für dich dürfte der "RoutesDispatcher" sein. Dafür musst du aber noch das "routes"-Paket mit "easy_install" installieren.

Hier ist ein Beispiel:

Code: Alles auswählen

#!/usr/bin/env python
#coding: utf-8
"""
Requirements
    - Python: http://python.org/
    - cherrypy: http://cherrypy.org/
    - routes: http://pypi.python.org/pypi/Routes/
"""

import cherrypy


class Root(object):
    
    def index(self, *args, **kwargs):
        retstr = (
            "Root-index<br>" +
            repr(args) + "<br>" +
            repr(kwargs)
        )
        return retstr
    index.exposed = True
    

class Users(object):
    
    def index(self, *args, **kwargs):
        retstr = (
            "Users-index<br>" +
            repr(args) + "<br>" +
            repr(kwargs)
        )
        return retstr
    index.exposed = True
    
    
    def get_user(self, *args, **kwargs):
        retstr = (
            "Users-get_user<br>" +
            repr(args) + "<br>" +
            repr(kwargs)
        )
        return retstr
    get_user.exposed = True
    
 
    def get_image(self, user, imageid):
        retstr = (
            "Users-get_image<br>" +
            "user: %s<br>" % user +
            "imageid: %s" % imageid
        )
        return retstr
    get_image.exposed = True

    
    def get_image_comment(self, user, imageid):
        retstr = (
            "Users-get_image_comment<br>" +
            "user: %s<br>" % user +
            "imageid: %s" % imageid
        )
        return retstr
    get_image_comment.exposed = True
    

def main():
    root = Root()
    root.users = Users()
    
    dispatcher = cherrypy.dispatch.RoutesDispatcher()
    dispatcher.connect(
        "users-index", "/users/", 
        controller = root.users, action = "index"
    )
    dispatcher.connect(
        "users-user", "/users/:user/", 
        controller = root.users, action = "get_user"
    )
    dispatcher.connect(
        "users-image", "/users/:user/images/:imageid", 
        controller = root.users, action = "get_image"
    )
    dispatcher.connect(
        "users-image-comment", "/users/:user/images/:imageid/comment", 
        controller = root.users, action = "get_image_comment"
    )

    app = cherrypy.tree.mount(root)
    conf = {"/users": {"request.dispatch" : dispatcher}}
    app.config.update(conf)
    cherrypy.quickstart(app)


if __name__ == "__main__":
    main()
Damit kannst du die oben genannten URLs verwenden.

mfg
Gerold
:-)

http://paste.pocoo.org/show/113472/
Zuletzt geändert von gerold am Mittwoch 22. April 2009, 13:43, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

Sehr schön! Vielen Dank. Das ist so ziemlich genau das wonach ich gesucht habe. Ich werde CherryPy für das projekt verwenden
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wobei das mit Werkzeug auch schön einfach zu lösen ist - und da braucht man kein extra Routes-Modul. Wo liegt da also nun der große Unterschied frag ich mich gerade? (Denn Werkzeug war dem OP ja irgend wie zu "wenig" Framework)
lunar

Werkzeug nimmt dem Programmierer wenig bis gar nichts ab, während CherryPy zumindest Sessionverwaltung, Routing und iirc auch Authentifizierung weitgehend automatisch kann.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

lunar hat geschrieben:Werkzeug nimmt dem Programmierer wenig bis gar nichts ab, während CherryPy zumindest Sessionverwaltung, Routing und iirc auch Authentifizierung weitgehend automatisch kann.
Ja ok, ich bezog mich grad auf das Routing, welches Werkzeug ebenso bietet (oder sehe ich das falsch?) - aber das andere sind da sicherlich Argumente für CherryPy. Da müßte man bei werkzeug ja wirklich noch Hand anlegen.

*seufz* Müßte dringend mal an meinen werkeug-Test-Applikationen weiter arbeiten ... wenn man doch mehr Zeit hätte ;-)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hyperion hat geschrieben:Wo liegt da also nun der große Unterschied frag ich mich gerade? (Denn Werkzeug war dem OP ja irgend wie zu "wenig" Framework)
Hallo Hyperion!

Ich schieße jetzt einfach mal in die Luft: Werkzeug ist, meiner Meinung nach, nicht so einfach zu benutzen wie CherryPy. Allein wenn ich mir das erste Beispiel anschaue, welches man auf diser Seite http://werkzeug.pocoo.org/ findet, fällt mir auf, dass CherryPy für mich einfacher zu benutzen ist.
CherryPy kümmert sich um die Sessionverwaltung, die Base-Authentifizierung, die Digest-Authentifizierung und um das Handling von abschließenden Slashes (/). Es stellt mir eine Konfigurationsumgebung zur Verfügung, mit welcher ich über eine INI-Datei oder selber über den Quellcode, Einstellungen verwalten kann. Weiters läuft CherryPy ohne großes Zutun mit mod_python und mod_wsgi. Es läuft aber auch als eigenständiger Server z.B. hinter einem Apachen mit mod_proxy.
Requests werden in einfach zu verwendende "cherrypy.request"-Objekte umgewandelt. Parameter (POST, GET,...), werden direkt als Parameter an die Funktion übergeben und können somit sehr einfach verwendet werden.
Von haus aus, wird eine sehr einfach gehaltene Strukturierung der URL über Klasseninstanzen vewendet. Wenn man, wie Jan.O, eine andere URL-Struktur haben möchte, dann kann man sich selber einen URL-Dispatcher schreiben und einbinden. Man kann aber auch bereits fertige Dispatcher einbinden. Usw...

Ich möchte keinen Streit lostreten. Mir persönlich gefällt die Art nicht, wie man mit Werkzeug arbeiten muss. Das ist aber nur eine persönliche Meinung und ich möchte niemanden beleidigen, der gerne mit Werkzeug arbeitet. Werkzeug ist sicher kein schlechtes Tool.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Hyperion hat geschrieben:
lunar hat geschrieben:Werkzeug nimmt dem Programmierer wenig bis gar nichts ab, während CherryPy zumindest Sessionverwaltung, Routing und iirc auch Authentifizierung weitgehend automatisch kann.
Ja ok, ich bezog mich grad auf das Routing, welches Werkzeug ebenso bietet (oder sehe ich das falsch?) - aber das andere sind da sicherlich Argumente für CherryPy. Da müßte man bei werkzeug ja wirklich noch Hand anlegen.
Werkzeug bietet ein Routing - ja, ebenso wie es auch noch andere Kleinigkeiten wie Securecookie und einige Datentypen die für Web-Arbeit nützlich sind. Aber du kannst es dir eher wie ``bsdutils`` vorstellen: eher ein Paket mit nützlichen Programmen die kleine Aufgaben erledigen. Niemand würde wohl auf die Idee kommen, alleine mit Werkzeug irgendeine Webapplikation zu bauen - dafür gibt es bereits genug WSGI-Tools, als das man das noch einmal implementieren müsste.

CherryPy macht hingegen etwas mehr Vorgaben (damit meine ich die Standardeinstellungen). Einige bevorzugen eher die Vorgaben (CherryPy, Django) und andere geben der Freiheit den Vorzug (Werkzeug). Hängt auch in irgendwieweit ab, was man genau implementieren will.

Edit: Pylons aus Auflistung entfernt, danke Lunar.
Zuletzt geändert von Leonidas am Donnerstag 23. April 2009, 13:58, insgesamt 1-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Leonidas & Gerodl: Danke für den kurzen "Vergleich". Ich muss mir wohl auch mal CherryPy angucken denke ich :-)
lunar

@Leonidas
pylons macht ebenfalls viele Vorgaben. Die Verzeichnisstruktur des Quellcodes ist vorgegeben, der Datenbankzugriff, das Routing, die Sessions, etc. Man kann es nur sehr, sehr leicht austauschen.
Jan.O
User
Beiträge: 61
Registriert: Samstag 26. April 2008, 00:32

gerold hat geschrieben: Damit kannst du die oben genannten URLs verwenden.
http://paste.pocoo.org/show/113472/
Und wie komme ich jetzt an die POST-Daten ran? xD
Antworten