librelist archives

« back to archive

Best way to use SQLAlchemy

Best way to use SQLAlchemy

From:
Giovanni Giorgi
Date:
2011-07-06 @ 09:10
Hi all,
 I am using the Flask-SQLAlchemy extension.
I have a simple question.
In the documentation, the getting started example fire a SQLAlchemy
object with something like

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)

I'd like instead using something like the one used by flaskr, because of
unit testing:

def connect_db():
    """Returns a new connection to the database."""
    return SQLAlchemy(app)

connect_db is called every time it is needed (for example inside a
@app.before_request handler).

Is this a good idea, or it will force to regenerate the SQLAlchemy
strutures every time, leading to a slow/bad approach?

Thank you, and sorry for the simple question...

-- 
Senior Consultant
http://gioorgi.com

Re: [flask] Best way to use SQLAlchemy

From:
Armin Ronacher
Date:
2011-07-06 @ 09:14
Hi,

On 7/6/11 11:10 AM, Giovanni Giorgi wrote:
> I'd like instead using something like the one used by flaskr, because of
> unit testing:
> 
> def connect_db():
>     """Returns a new connection to the database."""
>     return SQLAlchemy(app)
> 
> connect_db is called every time it is needed (for example inside a
> @app.before_request handler).
> 
> Is this a good idea, or it will force to regenerate the SQLAlchemy
> strutures every time, leading to a slow/bad approach?
That's generally not a good idea, but you can do something similar with
how SQLAlchemy works.  You create the application on the fly as you need
it an later initialize SQLAlchemy with it:

    db = SQLAlchemy()

    def create_app(config):
        app = Flask(__name__)
        app.config.update(config)
        register_views(app)
        db.init_app(app)
        return app

It's better to also couple that with blueprints, then you don't have to
create the views in a function:

    db = SQLAlchemy()
    frontend = Blueprint('frontend', __name__)

    @frontend.route('/')
    def index():
        ...

    def create_app(config):
        app = Flask(__name__)
        app.config.update(config)
        app.register_blueprint(frontend)
        db.init_app(app)
        return app


Regards,
Armin

Re: [flask] Best way to use SQLAlchemy

From:
Giovanni Giorgi
Date:
2011-07-06 @ 12:10
Hi,
 htank you for youtr hanswer, but I have some problem using the
init_app function of SQLAlchemy.
Here is the testcase, form a python prompt:

>>> app.config['SQLALCHEMY_DATABASE_URI']
'sqlite:///../devdb-sqlalchemy.sqlite3'
>>> db=SQLAlchemy()
>>> db
<SQLAlchemy engine=None>
>>> db.init_app(app)
>>> db
<SQLAlchemy engine=None>
>>> db2=SQLAlchemy(app)
>>> db2
<SQLAlchemy engine='sqlite:///../devdb-sqlalchemy.sqlite3'>
>>>

It seems the db variable is not properly
initialized if I do not pass 'app' to the SQLAlchemy constructor.
When I try to invoke db.create_all() I get
 RuntimeError: application not registered on db instance and no
application  bound to current context

db2 instance works great, instead.

Where am I wrong?
Thanks

On Wed, July 6, 2011 11:14 am, Armin Ronacher wrote:
> Hi,
>
> On 7/6/11 11:10 AM, Giovanni Giorgi wrote:
>> I'd like instead using something like the one used by flaskr, because of
>> unit testing:
>>
>> def connect_db():
>>     """Returns a new connection to the database."""
>>     return SQLAlchemy(app)
>>
>> connect_db is called every time it is needed (for example inside a
>> @app.before_request handler).
>>
>> Is this a good idea, or it will force to regenerate the SQLAlchemy
>> strutures every time, leading to a slow/bad approach?
> That's generally not a good idea, but you can do something similar with
> how SQLAlchemy works.  You create the application on the fly as you need
> it an later initialize SQLAlchemy with it:
>
>     db = SQLAlchemy()
>
>     def create_app(config):
>         app = Flask(__name__)
>         app.config.update(config)
>         register_views(app)
>         db.init_app(app)
>         return app
>
> It's better to also couple that with blueprints, then you don't have to
> create the views in a function:
>
>     db = SQLAlchemy()
>     frontend = Blueprint('frontend', __name__)
>
>     @frontend.route('/')
>     def index():
>         ...
>
>     def create_app(config):
>         app = Flask(__name__)
>         app.config.update(config)
>         app.register_blueprint(frontend)
>         db.init_app(app)
>         return app
>
>
> Regards,
> Armin
>


-- 
Senior Consultant
http://gioorgi.com

Re: [flask] Best way to use SQLAlchemy

From:
Armin Ronacher
Date:
2011-07-06 @ 12:37
Hi,

On 2011-07-06 2:10 PM, Giovanni Giorgi wrote:
> It seems the db variable is not properly
> initialized if I do not pass 'app' to the SQLAlchemy constructor.
It is, but it is initialized only when it's bound to an application.

> When I try to invoke db.create_all() I get
>   RuntimeError: application not registered on db instance and no
> application  bound to current context
You will need to do this:

    app = create_application()
    with app.test_request_context():
        db.create_all()

Why?  Because the with statement binds the test-request context to the 
current thread and this way the SQLAlchemy extensions can figure out the 
current settings.  Alternatively you can also do db.create_all(app=app) 
I think.


Regards,
Armin

Re: [flask] Best way to use SQLAlchemy

From:
Giovanni Giorgi
Date:
2011-07-06 @ 15:48
Thank you,
 I have fixed the init db, but I am unable to do tests.
First of all, I was unable to find register_views on Flask package,
so it is missed on my create_app() function.

I ended up with  something like:
    def setUp(self):
        """Before each test, set up a blank database"""
        wpWebPublisher.app.config['SQLALCHEMY_DATABASE_URI']="sqlite:///:memory:"
        wpWebPublisher.app.config['TESTING'] = True
        # Update my config....
        wpWebPublisher.app=wpWebPublisher.create_app(wpWebPublisher.app.config)
        self.app = wpWebPublisher.app.test_client()
        wpWebPublisher.init_db()

It seems ok, but when I try to run simple test like

self.app.get('/about',follow_redirects=True)

I get a 404 error... I need to create a test request also?
Why flaskr_test.py needn't it? :)






On Wed, July 6, 2011 2:37 pm, Armin Ronacher wrote:
> Hi,
>
> On 2011-07-06 2:10 PM, Giovanni Giorgi wrote:
>> It seems the db variable is not properly
>> initialized if I do not pass 'app' to the SQLAlchemy constructor.
> It is, but it is initialized only when it's bound to an application.
>
>> When I try to invoke db.create_all() I get
>>   RuntimeError: application not registered on db instance and no
>> application  bound to current context
> You will need to do this:
>
>     app = create_application()
>     with app.test_request_context():
>         db.create_all()
>
> Why?  Because the with statement binds the test-request context to the
> current thread and this way the SQLAlchemy extensions can figure out the
> current settings.  Alternatively you can also do db.create_all(app=app)
> I think.
>
>
> Regards,
> Armin
>


-- 
Senior Consultant
http://gioorgi.com