2013-11-04 12 views
6

Hintergrund: Flask/Flask-SQLAlchemy/Flask-WTF, unter Verwendung von deklarativen und scoped SitzungSQLAlchemy Sitzungen Fehler

Einfache POST Betrieb:

@tas.route('/order_add', methods=['GET', 'POST']) 
def tas_order_add(): 
    if request.method == 'POST': 
     order_form = OrderForm() 
     if order_form.validate_on_submit(): 
      order = Order() 
      order_form.populate_obj(order) 
      db_session.add(order) 
      db_session.commit() 

Jetzt versucht, es zu laufen bekomme ich einen Fehler:

InvalidRequestError: Object '' is already attached to session '1' (this is '2')

Ändern hinzufügen löst das Problem zu fusionieren, aber:

  • Ich weiß nicht, warum ich ein Objekt verschmelzen, während ich es nur
  • initiiert
  • Wenn ich hinzufügen, ändern sich zu fusionieren und versuchen Sie eine der Eigenschaften etwas in Zeile

    definieren
    order = Order() 
    order_form.populate_obj(order) 
    order.order_status = OrderStatus.query.filter(OrderStatus.code=='PLACED').first() 
    db_session.merge(order) 
    db_session.commit() 
    

    ich bekomme den gleichen Fehler, gerade jetzt auf Orderstatus Objekt

    InvalidRequestError: Object '' is already attached to session '2' (this is '1')

Kann mir jemand zeigen, wo ich etwas falsch tue, weil es mich verrückt fährt. Ich habe etwas Erfahrung mit SQLAlchemy, aber es ist das erste Mal, dass ich ein solches Verhalten sehe und ich kann das Problem nicht lokalisieren.

Suche alles, was ich fand, war ein Problem mit der doppelten Datenbanksitzung Initialisierung, aber ich glaube nicht, es ist dieser Fall.

EDIT

db_session wird in separaten Datei database.py definiert mit Inhalt folgenden

from sqlalchemy.engine import create_engine 
from sqlalchemy.ext.declarative.api import declarative_base 
from sqlalchemy.orm.scoping import scoped_session 
from sqlalchemy.orm.session import sessionmaker 

engine = create_engine('sqlite:///fundmanager_devel.db', convert_unicode=True) 
db_session = scoped_session(sessionmaker(autocommit=False, 
             autoflush=False, 
             bind=engine)) 
Base = declarative_base() 
Base.query = db_session.query_property() 
+0

wo ist db_session definiert? Kannst du den Code dafür hinzufügen? –

+0

Als Bearbeitung zur Frage hinzugefügt –

Antwort

4

so seltsam ist. Warum erstellen Sie die Engine und die deklarative Basis explizit, wenn Sie flask-sqlalchemy verwenden? Das ist wahrscheinlich, wo dein Problem ist. Es sieht so aus, als hätten Sie zwei Engines und Sitzungen, die gleichzeitig laufen, deshalb haben Sie den Fehler bekommen.

Statt den Motor explizit zu schaffen, sollten Sie nur verwenden:

from flask.ext.sqlalchemy import SQLAlchemy 

db = SQLAlchemy() 

Und in Ihrer App Fabrik:

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///fundmanager_devel.db' 
db.init_app(app) 

Dann Ihre Basis Vereinbarungsmodell db.Model Ihre Sitzung ist in db.session, und Sie sollten den Kontext von flask anfordern, um die Erstellung von Sitzungen zu verwalten.

Überprüfen Sie die minimale Anwendungsbeispiel in Flask-SQLAlchemy docs:

http://pythonhosted.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application

Dies ist, wie es von SQLAlchemy empfohlen wird:

Most web frameworks include infrastructure to establish a single Session, associated with the request, which is correctly constructed and torn down corresponding torn down at the end of a request. Such infrastructure pieces include products such as Flask-SQLAlchemy, for usage in conjunction with the Flask web framework, and Zope-SQLAlchemy, for usage in conjunction with the Pyramid and Zope frameworks. SQLAlchemy strongly recommends that these products be used as available.

http://docs.sqlalchemy.org/en/rel_0_9/orm/session.html

+0

Ich habe einige Dokumente gelesen, dass es so ist, wie es definiert werden sollte. Ich habe eine laufende Anwendung mit Setup so, und es verursachte keine Probleme. Ich nehme deinen Rat und ändere mein Setup und berichte zurück –

+0

So verwenden Sie es in einer SQLAlchemy-Anwendung ohne Flask. Wenn Sie Flask oder ein anderes Framework verwenden, sollten Sie die bereitgestellte Infrastruktur verwenden, um sicherzustellen, dass eine einzige Sitzung stattfindet. Ich habe meine Antwort bearbeitet, um die SQLAlchemy-Dokumente hinzuzufügen, die diesen Punkt erwähnen. –

+0

Das ist wahrscheinlich nicht mein Problem. Ich habe meine App geändert, um nicht deklarativ zu verwenden, aber das Problem besteht weiterhin. Ich vermute, es ist eine Sache, dass meine init mit db-Initialisierung zweimal ausgeführt wird (checked it mit print debug) und erstellt db-Verbindung zweimal. Ich kann das Problem nicht finden, ich habe App Setup mit Tutorials gemacht. Es muss etwas wirklich Dummes sein, aber ich kann es einfach nicht finden. –

5

scheint ein Problem mit Session-Mix Ich benutzte es wie folgt und es funktioniert:

+0

Die Verwendung von 'db.session.query (Category)' anstelle von 'Category.query.all()' hat für mich funktioniert. Vielen Dank! –

5

Ich hatte ein ähnliches Problem mit QuerySelectField:

forms.py:

class SurgeryForm(Form): 
    study = QuerySelectField('Study', 
          query_factory=StudyGroup.query.all, 
          get_label='name') 

models.py

class Animal(db.Model): 
    study_id = db.Column(db.Integer, db.ForeignKey('study_group.id')) 

class StudyGroup(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(50)) 
    animals = db.relationship('Animal', backref='group', lazy='dynamic') 

views.py:

def do_surgery(): 
    form = SurgeryForm(request.form) 

    if form.validate_on_submit(): 
     a = models.Animal() 
     form.populate_obj(a) # Gather the easy stuff automagically 
     #a.group = form.data['study'] #FAILS! 
     a.study_id = form.data['study'].id #WORKS! 

Es scheint, dass SQLAlchemy (oder möglicherweise Flask-SQLAlchemy oder Flask-WTF) verwendet eine Sitzung zum Sammeln der Werte im QuerySelectField und eine weitere Sitzung zum Erstellen des neuen Animal-Objekts.

Wenn Sie versuchen, das StudyGroup-Objekt mithilfe der backref (Animal.group) an das Animal anzuhängen, werden Sie auf dieses Problem stoßen (da die Objekte mit verschiedenen Sitzungen verknüpft sind). Die Problemumgehung, die ich verwende, besteht darin, den Fremdschlüssel (Animal.study_id) direkt festzulegen.

Klar bin ich ein wenig zu spät zur Party mit dieser Antwort, aber ich hoffe, es hilft jemandem!