2015-11-30 12 views
5

Mam widok kolby, który używa SQLAlchemy do wysyłania kwerend i wyświetlania niektórych wpisów na blogu. Używam aplikacji, używając mod_wsgi. Ten widok działa po raz pierwszy na stronie, ale następnym razem zwraca błąd 500. Funkcja traceback pokazuje błąd. ProgrammingError: SQLite objects created in a thread can only be used in that same thread. Dlaczego pojawia się ten błąd i jak mogę go naprawić?Korzystanie z sesji SQLAlchemy z Flask podnosi "Obiekty SQLite utworzone w wątku mogą być używane tylko w tym samym wątku"

views.py

engine = create_engine('sqlite:////var/www/homepage/blog.db') 
Base.metadata.bind = engine 
DBSession = sessionmaker(bind = engine) 
session = DBSession() 

@app.route('/blog') 
@app.route('/blog.html') 
def blog(): 
    entrys = session.query(Entry).order_by(desc(Entry.timestamp)).all() 
    return render_template('blog.html', blog_entrys = entrys) 

models.py:

class Entry(Base): 
    __tablename__ = 'entry' 

    id = Column(Integer, primary_key = True) 

    title = Column(String(100), nullable = False) 
    body = Column(String, nullable = False) 
    timestamp = Column(DateTime, nullable = False) 
    featured = Column(Boolean, nullable = False) 

    comments = relationship('Comment') 

    def is_featured(self): 
     return self.featured 


class Comment(Base): 
    __tablename__ = 'comment' 

    id = Column(Integer, primary_key = True) 
    entry_id = Column(Integer, ForeignKey('entry.id')) 

    text = Column(String(500), nullable = False) 
    name = Column(String(80)) 


engine = create_engine('sqlite:////var/www/homepage/blog.db') 
Base.metadata.create_all(engine) 
Exception on /blog.html [GET] 
Traceback (most recent call last): 
    File "/usr/lib/python2.6/dist-packages/flask/app.py", line 861, in wsgi_app 
    rv = self.dispatch_request() 
    File "/usr/lib/python2.6/dist-packages/flask/app.py", line 696, in dispatch_request 
    return self.view_functions[rule.endpoint](**req.view_args) 
    File "/var/www/homepage/webserver.py", line 38, in blog 
    entrys = session.query(Entry).order_by(desc(Entry.timestamp)).all() 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 1453, in all 
    return list(self) 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 1565, in __iter__ 
    return self._execute_and_instances(context) 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 1570, in _execute_and_instances 
    mapper=self._mapper_zero_or_none()) 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/session.py", line 735, in execute 
    clause, params or {}) 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1157, in execute 
    params) 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1235, in _execute_clauseelement 
    parameters=params 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1348, in __create_execution_context 
    None, None) 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1343, in __create_execution_context 
    connection=self, **kwargs) 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/engine/default.py", line 381, in __init__ 
    self.cursor = self.create_cursor() 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/engine/default.py", line 523, in create_cursor 
    return self._connection.connection.cursor() 
    File "/usr/lib/python2.6/dist-packages/sqlalchemy/pool.py", line 383, in cursor 
    c = self.connection.cursor(*args, **kwargs) 
ProgrammingError: (ProgrammingError) SQLite objects created in a thread can only be used in that same thread.The object was created in thread id 140244498364160 and this is thread id 140244523542272 None [{}] 

Odpowiedz

6

SQLAlchemy (aw tym przypadku również SQLite) nie działa, jeśli dzielić sesję drugiej nici. Możesz nie używać jawnie wątków, ale jest to mod_wsgi i zdefiniowałeś globalny obiekt session. Albo użyj scoped_session do obsługi tworzenia unikalnej sesji dla każdego wątku.

session = scoped_session(sessionmaker(bind=engine)) 

@app.teardown_request 
def remove_session(ex=None): 
    session.remove() 

@app.route('/') 
def example(): 
    item = session.query(MyModel).filter(...).all() 
    ... 

Korzystnie używać Flask-SQLAlchemy który obsługuje ten i inne rzeczy dla Ciebie. Dokumenty SQLAlchemy zalecają korzystanie z biblioteki integracyjnej, zamiast robić to samemu.

db = SQLAlchemy(app) 

@app.route('/') 
def example(): 
    item = db.session.query(MyModel).filter(...).all() 
    ... 

Należy również pamiętać, że powinno być zdefiniowanie tylko silnik, sesji itp raz i importowanie go gdzie indziej, zamiast przedefiniowanie go w każdym pliku jak aktualna kod robi.

+0

Pracował. W szczególności zaimportowałem scoped_session z sqlalchemy.orm, a następnie utworzyłem obiekt "SessionParent", jak opisano w tym przewodniku http://docs.sqlalchemy.org/en/latest/orm/contextual.html –

2

Biorąc podpowiedź z this SO answer Szukałem docs SA i okazało się, można to zrobić:

engine = create_engine('sqlite:////var/www/homepage/blog.db?check_same_thread=False') 

scoped_session nie było odpowiednie w moim przypadku, ponieważ kolba-SQLAlchemy zajmuje tylko argument ciąg połączenia:

from flask import Flask 
from flask_sqlalchemy import SQLAlchemy 


class Config(object): 
    SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db?check_same_thread=False' 


db = SQLAlchemy() 


def create_app(): 
    app.config.from_object(Config) 
    app = Flask(__name__) 
    db.init_app(app) 
    ... 
Powiązane problemy