Logikproblem SQLAlchemy

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Hallo,

ich habe ein Problem mit Sqlalchemy. Und zwar speichere ich das Userobjekt nach dem Login innerhalb von session in Flask.
Wenn ich nun aber nachträglich darauf zugreife, kommt folgende Fehlermeldung:

sqlalchemy.orm.exc.DetachedInstanceError
DetachedInstanceError: Parent instance <UserGroup at 0xb53c42cc> is not bound to a Session; lazy load operation of attribute 'rights' cannot proceed

Ich denke, das hängt doch irgendwie damit zusammen. Was kann ich tun, damit die Objekte (und auch deren Attribute) immer erreichbar bleiben?

Vielen Dank.
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Das hört sich irgendwie etwas seltsam an, was du da versuchst. Hast du ein kleines Codebeispiel?
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Und Du glaubst ernsthaft, dass Dir jetzt irgend jemand ohne Deinen Code, ohne lauffähiges Minimalbeispiel oder irgend eine Form von detaillierten Beschreibungen, *was* Du in Deinem Code machst, diese Frage beantowrten kann? Bei allem Respekt, aber als erfahrener User hier im Forum solltest Du doch wissen, dass Du schon ausreichend Informationen posten musst, um eine produktive Antwort zu erhalten!

Man kann hier nur die Fehlermeldung (die Du auch in Code-Tags setzen solltest!) wiederholen: Das `UserGroup`-Objekt ist nicht an eine (SQLALchemy-)Session gebunden - wieso, dass kann hier niemand ohne Code sagen ;-)

Nebenbei: Sowohl Flask als auch SQLALchemy besitzen "Session"-Objekte - auch dahingehend erscheint mir Dein Beitrag viel zu unpräzise bzw. uneindeutig.

Da Flask out of the box gar keine SQLAlchemy-Unterstützung anbietet, wissen wir ja auch nicht einmal, wie Du diese umsetzt. Baust Du Dir alles selber zusammen, oder nutzt Du ein Plugin für Flask? Wie genau gehst Du dann vor?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Ohje, das tut mir leid. Zu wenig Informationen wollte ich auf keinen Fall geben, es war mir nur nicht ganz klar, wie ich das am besten rüberbringe, weil lauffähiger Code wird etwas schwierig :-/

UserGroup:

Code: Alles auswählen

class UserGroup(object):
    
    link = None
    id = None
    name = None
    
    def __init__(self,**kwargs):
        self.link = database.query(database.UserGroup).filter_by(**kwargs).first()
        if not self.link: 
            raise lib.exceptions.NotExistingError
        self.id = self.link.id
        self.name = self.link.name
    
    @staticmethod
    def search(**kwargs):
        l = []
        for x in database.query(database.UserGroup).filter_by(**kwargs):
            l.append(UserGroup(id=x.id))
        return l
    
    @staticmethod
    def create(name,**kwargs):
        if UserGroup.search(name=name):
            raise lib.exceptions.AlreadyExistingError
        g = database.UserGroup(name=name,**kwargs)
        g.create()
        g2 = UserGroup(id=g.id)
        return g2
    
    @property
    def rights(self):
        l = []
        for x in self.link.rights:
            l.append(UserRight.search(id=x.id)[0])
        return l
    
    def allowed(self,right):
        for x in self.rights:
            if x.name == right:
                return True
        return False
    
    def allow(self,right):
        if type(right) == str:
            right = UserRight(name=right)
        if self.allowed(right.name):
            return True
        self.link.rights.append(right.link)
        self.save()
        return True
    
    def forbid(self,right):
        if type(right) == str:
            right = UserRight(name=right)
        if not self.allowed(right.name):
            return True
        for c,x in enumerate(self.link.rights):
            if x.name == right.name:
                del(self.link.rights[c])
        self.save()
        return True

    
    def save(self):
        database.do(self.link)
    
    def __repr__(self):
        return "<UserGroup %s>" % (self.name)   

Das Datenbankbackend:

Code: Alles auswählen

class UserGroup(Base):
    __tablename__ = "groups"
    
    id = Column(Integer, primary_key=True)
    name = Column(Text)
    rights = relationship("UserRight",secondary=usergroup_userright,backref="groups")

    def create(self):
        do(self)
        return self
    
    def __repr__(self):
        return "<Database:UserGroup (%s)" % (self.name)
Im Programmcode verwende ich das Sessionobjekt von Flask.

dies wird folgendermaßen verwendet:

Code: Alles auswählen

@app.route("/login",methods=["POST","GET"])
def login():
    if request.method != "POST":
        return templates.load("login.tpl").render(session=session)
    else:
        username = request.form["username"]
        password = request.form["password"]
        if not User.check(username,password):
            return "Error!"
        user = User(username=username)
        user.login(password)
        session["user"] = user
        return redirect(url_for("management"))
Die eigentliche Fehlermeldung entsteht hierbei bei folgendem Code:

Code: Alles auswählen

def check_permission(session,right):
    if not session["user"]:
        return False
    if not session["user"].allowed(right):
        return False
    return True
Ich hoffe, die Codebeispiele helfen euch etwas, ihr könnt aber gerne jederzeit nachfragen. Meine größte Sorge ist, dass ich hier einen riesengroßen Logikfehler eingebaut habe :-/
BlackJack

@sprudel: Ich vermute mal das sie Session-Daten in der DB gespeichert werden und die SQLAlchemy-Objekte das (de)serialisieren nicht überleben, zumindest nicht komplett. In so einer Session würde ich nichts allzu komplexes speichern. Eher die User-ID und damit dann das Objekt aus der DB holen.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Hmm, du vermutest also, dass das Problem ist, dass ich das gesamte Objekt in der Session speichere, und nicht nur eine einfache UserID?
Das klingt natürlich logisch, und das habe ich mir ehrlich gesagt so noch garnicht überlegt.
Findest du denn sonst noch irgendwelche groben Fehler in meinem Code? Ich bin bei der Programmierung zugegebenermaßen noch etwas unsicher, ob überhaupt mein Modell (mit den getrennten Objekten usw.) passt :-)
Antworten