From 53a38059216392bdb52028c6e6d9fb81c827b759 Mon Sep 17 00:00:00 2001 From: Friedrich Lindenberg Date: Wed, 3 Oct 2012 19:19:58 +0200 Subject: [PATCH] Switch to flask-sqlalchemy to dispose of connections properly --- pybossa/core.py | 2 ++ pybossa/model.py | 31 +++++++++++-------------------- pybossa/web.py | 21 --------------------- requirements.txt | 1 + test/base.py | 4 ++-- 5 files changed, 16 insertions(+), 43 deletions(-) diff --git a/pybossa/core.py b/pybossa/core.py index ce2469860f..a44a8d8052 100644 --- a/pybossa/core.py +++ b/pybossa/core.py @@ -18,6 +18,7 @@ from flask import Flask from flaskext.login import LoginManager, current_user from flaskext.gravatar import Gravatar +from flask.ext.sqlalchemy import SQLAlchemy from pybossa import default_settings as settings @@ -71,4 +72,5 @@ def setup_logging(app): login_manager.login_view = "/account/signin" login_manager.login_message = u"Please sign in to access this page." app = create_app() +db = SQLAlchemy(app) diff --git a/pybossa/model.py b/pybossa/model.py index c451dcfd50..41dc3a505a 100644 --- a/pybossa/model.py +++ b/pybossa/model.py @@ -23,39 +23,31 @@ from werkzeug import generate_password_hash, check_password_hash import flaskext.login -from sqlalchemy import create_engine from sqlalchemy import BigInteger, Integer, Boolean, Unicode,\ Float, UnicodeText, Text, String from sqlalchemy.schema import Table, MetaData, Column, ForeignKey from sqlalchemy.orm import relationship, backref, class_mapper -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.types import MutableType, TypeDecorator from sqlalchemy import event +from pybossa.core import db from pybossa.util import pretty_date log = logging.getLogger(__name__) -Session = scoped_session(sessionmaker()) - - -def set_engine(engine): - Base.metadata.bind = engine - +Session = db.session def make_timestamp(): now = datetime.datetime.now() return now.isoformat() - def make_uuid(): return str(uuid.uuid4()) def rebuild_db(): - Base.metadata.drop_all() - Base.metadata.create_all() + db.drop_all() + db.create_all() # ========================================= # Basics @@ -98,6 +90,7 @@ class StateEnum: class DomainObject(object): + def dictize(self): out = {} for col in self.__table__.c: @@ -124,13 +117,10 @@ def __unicode__(self): return repr -Base = declarative_base(cls=DomainObject) - - # ========================================= # Domain Objects -class App(Base): +class App(db.Model, DomainObject): '''A microtasking Application to which Tasks are associated. ''' __tablename__ = 'app' @@ -201,7 +191,7 @@ def last_activity(self): return "None" -class Featured(Base): +class Featured(db.Model, DomainObject): '''A Table with Featured Apps. ''' __tablename__ = 'featured' @@ -213,7 +203,7 @@ class Featured(Base): app_id = Column(Integer, ForeignKey('app.id')) -class Task(Base): +class Task(db.Model, DomainObject): '''An individual Task which can be performed by a user. A Task is associated to an App. ''' @@ -263,7 +253,7 @@ def pct_status(self): return float(0) -class TaskRun(Base): +class TaskRun(db.Model, DomainObject): '''A run of a given task by a specific user. ''' __tablename__ = 'task_run' @@ -296,7 +286,7 @@ class TaskRun(Base): ''' -class User(Base, flaskext.login.UserMixin): +class User(db.Model, DomainObject, flaskext.login.UserMixin): __tablename__ = 'user' id = Column(Integer, primary_key=True) #: created timestamp (automatically set) @@ -350,3 +340,4 @@ def make_admin(mapper, conn, target): if users == 0: target.admin = True #print "User %s is the first one, so we make it an admin" % target.name + diff --git a/pybossa/web.py b/pybossa/web.py index 819a7a0d1a..4a82ca1653 100644 --- a/pybossa/web.py +++ b/pybossa/web.py @@ -68,19 +68,6 @@ def url_for_other_page(page): return url_for(request.endpoint, **args) app.jinja_env.globals['url_for_other_page'] = url_for_other_page -@app.before_request -def bind_db_engine(): - dburi = app.config.get('SQLALCHEMY_DATABASE_URI', '') - if dburi: - engine = model.create_engine(dburi) - model.set_engine(engine) - else: - flash('You have not yet configured the database', 'error') - -@app.teardown_request -def teardown_request(exception): - model.Session.close() - #@app.errorhandler(401) #@app.errorhandler(403) #@app.errorhandler(404) @@ -116,11 +103,6 @@ def global_template_context(): @login_manager.user_loader def load_user(username): - # HACK: this repetition is painful but seems that before_request not yet called - # TODO: maybe time to use Flask-SQLAlchemy - dburi = app.config.get('SQLALCHEMY_DATABASE_URI', '') - engine = model.create_engine(dburi) - model.set_engine(engine) return model.Session.query(model.User).filter_by(name=username).first() @app.before_request @@ -131,9 +113,6 @@ def api_authentication(): if 'Authorization' in request.headers: apikey = request.headers.get('Authorization') if apikey: - dburi = app.config.get('SQLALCHEMY_DATABASE_URI', '') - engine = model.create_engine(dburi) - model.set_engine(engine) user = model.Session.query(model.User).filter_by(api_key=apikey).first() ## HACK: # login_user sets a session cookie which we really don't want. diff --git a/requirements.txt b/requirements.txt index c44c7dc795..5e198eee2b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ Flask-Login==0.1 Flask-WTF==0.6 Flask-Gravatar Flask-OAuth +Flask-SQLAlchemy dateutils alembic psycopg2 diff --git a/test/base.py b/test/base.py index a8dfdd49e7..3cd285541d 100644 --- a/test/base.py +++ b/test/base.py @@ -7,8 +7,8 @@ _here = os.path.dirname(__file__) web.app.config['TESTING'] = True web.app.config['SQLALCHEMY_DATABASE_URI'] = web.app.config['SQLALCHEMY_DATABASE_TEST_URI'] -engine = model.create_engine(web.app.config['SQLALCHEMY_DATABASE_URI']) -model.set_engine(engine) +#engine = model.create_engine(web.app.config['SQLALCHEMY_DATABASE_URI']) +#model.set_engine(engine) class Fixtures: fullname = u'T Tester'