On Wednesday, August 22, 2012 3:12:02 PM UTC+1, Simon King wrote: > > On Wed, Aug 22, 2012 at 2:44 PM, David McKeone > <davidm...@gmail.com<javascript:>> > wrote: > > > > > > On Wednesday, August 22, 2012 2:33:01 PM UTC+1, David McKeone wrote: > >> > >> > >> > >> On Wednesday, August 22, 2012 2:23:28 PM UTC+1, Simon King wrote: > >>> > >>> On Wed, Aug 22, 2012 at 12:51 PM, David McKeone <davidm...@gmail.com> > >>> wrote: > >>> > I've been using SQLAlchemy with Flask via the Flask extension > >>> > Flask-SQLAlchemy. Everything works great so far, but I foresee a > >>> > potential > >>> > problem once I start to use my database model outside of Flask. In > the > >>> > future I'd like to be able to use my models with non-Flask > SQLAlchemy > >>> > (a > >>> > worker daemon process or with a PySide interface). "Well just use > >>> > standard > >>> > SQLAlchemy," you may say, " and fore-go the use of the extension". > >>> > That was > >>> > my first thought, but sadly some useful extensions (notably > >>> > Flask-DebugToolbar) seem to like using the extension version and it > is > >>> > nice > >>> > to be able to have Flask manage the database sessions in the way > that > >>> > it > >>> > does. I'd like to not throw the baby out with the bath water. > >>> > > >>> > I realize that this is somewhat specific to Flask, but is there a > way > >>> > that I > >>> > could do both? Can I create models with standard SQLAlchemy > >>> > declarative and > >>> > then somehow inject them into Flask-SQLAlchemy's way of doing > things? > >>> > > >>> > If it helps with the solution, I don't need to use any of the Model > >>> > specific > >>> > methods that Flask-SQLAlchemy provides (get_or_404, paginate, etc..) > >>> > and I > >>> > also specify a __tablename__ for all of my models, so I don't rely > on > >>> > Flask-SQLAlchemy generating that for me. > >>> > > >>> > I took a look at the source of Flask-SQLAlchemy > >>> > > >>> > ( > https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py) > > > >>> > and from what I can tell it seems that it's using Flask's signalling > >>> > capabilities by customizing SQLAlchemy's session and mapper, but > that > >>> > is > >>> > where my understanding ends (I'm still new to this whole stack, > Python, > >>> > Flask, SQLAlchemy) and I could use some pointers for how to proceed. > >>> > > >>> > > >>> > To visualize what I'm talking about, here are the two types of > models. > >>> > A > >>> > basic Flask-SQLAlchemy model looks like > >>> > > >>> > ( > http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application): > > > >>> > > >>> > from flask import Flask > >>> > from flask.ext.sqlalchemy import SQLAlchemy > >>> > > >>> > app = Flask(__name__) > >>> > app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' > >>> > > >>> > db = SQLAlchemy(app) > >>> > > >>> > class User(db.Model): > >>> > id = db.Column(db.Integer, primary_key=True) > >>> > username = db.Column(db.String(80), unique=True) > >>> > email = db.Column(db.String(120), unique=True) > >>> > > >>> > def __init__(self, username, email): > >>> > self.username = username > >>> > > >>> > self.email = email > >>> > > >>> > > >>> > def __repr__(self): > >>> > return '<User %r>' % self.username > >>> > > >>> > > >>> > Note the db.Model, db.Integer and db <dot> everything. > >>> > > >>> > The plain declarative SQLAlchemy equivalent would be > >>> > (http://flask.pocoo.org/docs/patterns/sqlalchemy/): > >>> > > >>> > > >>> > from sqlalchemy import Column Integer, String, create_engine > >>> > from sqlalchemy.orm import scoped_session, sessionmaker > >>> > from sqlalchemy.ext.declarative import declarative_base > >>> > > >>> > engine = create_engine('sqlite:////tmp/test.db', > convert_unicode=True) > >>> > db_session = scoped_session(sessionmaker(autocommit=False, > >>> > autoflush=False, > >>> > bind=engine)) > >>> > Base = declarative_base() > >>> > Base.query = db_session.query_property() > >>> > > >>> > > >>> > class User(Base): > >>> > __tablename__ = 'users' > >>> > > >>> > id = Column(Integer, primary_key=True) > >>> > name = Column(String(50), unique=True) > >>> > email = Column(String(120), unique=True) > >>> > > >>> > def __init__(self, name=None, email=None): > >>> > self.name = name > >>> > self.email = email > >>> > > >>> > def __repr__(self): > >>> > return '<User %r>' % (self.name) > >>> > > >>> > >>> From a very quick read of the Flask-SQLAlchemy docs, I would have > >>> thought you could just use your flask-based classes in non-Flask-based > >>> apps without any issue. The quickstart guide that you referenced above > >>> illustrates a command-line session using them, so there's no reason > >>> why you couldn't do the same in a worker process. > >>> > >>> Have you already tried it and found that it doesn't work? > >>> > >>> Simon > >> > >> > >> > >> Perhaps I've missed the important bit, but my understanding is that > there > >> are two ways to do it: > >> > >> 1) Use SQLAlchemy with manual session control > >> (http://flask.pocoo.org/docs/patterns/sqlalchemy/) > >> 2) Use SQLAlchemy with the Flask-SQLAlchemy extension which does > session > >> control for you, but requires you to use it's own declarative base > class, > >> db.Model > >> ( > http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application) > > > >> > >> The problem is that other extensions give you additional features if > you > >> use solution #2, but not if you use solution #1, because solution #1 > implies > >> that you are going to do everything yourself manually. I'm fine with > the > >> way solution #2 handles the sessions and everything else, I just want > to be > >> able to use my own declarative base so that the models are more-or-less > >> independent of the app that they are being used in. > > > > > > I did a re-read of the documentation and I'm guessing this is the part > of > > the documentation you are referring to: > > http://packages.python.org/Flask-SQLAlchemy/contexts.html > > > > That basically says to use: app.test_request_context() before doing what > you > > do, so that it can establish a new context. I suppose that does make > sense, > > I guess i just viewed it as being only for testing and not for > application > > use. I would have thought it might be strange to include Flask in a > worker > > daemon when it isn't actually servicing http requests. > > > > Disclaimer: I've never used Flask so everything I say here could be > rubbish. Your question really seems to be 'How can I make > Flask-SQLAlchemy work with "standard" SQLAlchemy classes?', which is > probably better asked in a Flask-SQLAlchemy forum. > > It looks like the test_request_context method is only needed if you > don't have a Flask app object available when you define your model > classes. > > An (admittedly ugly) alternative would be to do something like this: > > #------------------------ > from flask import Flask > from flask.ext.sqlalchemy import SQLAlchemy > > class Bunch(object): > def __init__(self, **kwargs): > self.__dict__.update(kwargs) > > def get_model(app=None): > if app is None: > app = Flask(__name__) > db = SQLAlchemy(app) > > class User(db.Model): > id = db.Column(db.Integer, primary_key=True) > username = db.Column(db.String(80), unique=True) > email = db.Column(db.String(120), unique=True) > > def __init__(self, username, email): > self.username = username > self.email = email > > def __repr__(self): > return '<User %r>' % self.username > > return Bunch(**locals()) > > if __name__ == '__main__': > model = get_model() > model.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' > model.db.create_all() > user = model.User('Joe', 'j...@example.com <javascript:>') > model.db.session.add(user) > model.db.session.commit() > print model.db.session.query(model.User).all() > > #------------------------ > > Non-flask apps could just call the get_model() function and be > completely unaware that flask is in use under the hood. Flask apps > would pass their "app" instance into the get_model function. > > This might only be suitable for non-flask apps that use a single > thread and session, but perhaps that is sufficient. > > Hope that helps, > > Simon >
Yes, that solution seems to be the only way to do it. Use the flask-SQLAlchemy models and include a 'fake' flask session when doing something outside of flask. I had thought about asking on the Flask forum, but then it seemed like it might be too specific to the way that SQLAlchemy worked. Modifying it slightly though, I think you can just get away with using the app and the context manager: from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy class Bunch(object): def __init__(self, **kwargs): self.__dict__.update(kwargs) def get_model(app=None): if app is None: app = Flask(__name__) db = SQLAlchemy(app) class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True) email = db.Column(db.String(120), unique=True) def __init__(self, username, email): self.username = username self.email = email def __repr__(self): return '<User %r>' % self.username return Bunch(**locals()) if __name__ == '__main__': app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' db = SQLAlchemy(app) with app(): db.create_all() user =User('Joe', 'j...@example.com') print User.query.all() -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/-M1WncwtqT0J. To post to this group, send email to sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.