librelist archives

« back to archive

declarative sqlalchemy

declarative sqlalchemy

From:
Tom Borthwick
Date:
2011-11-07 @ 02:58
Hello,

I'm just starting with python and this is more of a beginning
python/SqlAlchemy question, but following the declarative instructions
on http://flask.pocoo.org/docs/patterns/sqlalchemy/, what's the best
way to pass in the database uri rather than hard-code it? Is it really
a best practice to have the uri used in the global engine var or is
that just for demonstration?

Thanks,

Tom

Re: [flask] declarative sqlalchemy

From:
Sean Chittenden
Date:
2011-11-07 @ 05:27
* Tom Borthwick <tborthwick@gmail.com> [2011-11-06 20:58:45 -0600]:

>I'm just starting with python and this is more of a beginning
>python/SqlAlchemy question, but following the declarative instructions
>on http://flask.pocoo.org/docs/patterns/sqlalchemy/, what's the best
>way to pass in the database uri rather than hard-code it? Is it really
>a best practice to have the uri used in the global engine var or is
>that just for demonstration?

This should answer a few questions that have come up recently regarding
templates, databases/SQLAlchemy and Blueprints.

This is how I'm currently structuring apps now that we're in a
post-Blueprints world. Figuring out this structure took a number of
iterations, but it seems sane-enough now. -sc


1) I put a default SQLALCHEMY_DATABASE_URI string in
    myapp/default_settings.py:

#+begin_src python
DATABASE_URI_FMT = 
'postgresql+psycopg2://{username}:{password}@{hostname}:{port}/{dbname}'
DB_PASS = ''
DB_PORT = '5432'
DB_SCHEMA = 'initial_schema'
DB_ADMIN = 'dba_role'
DB_USER = 'app_user'

from local_settings import *
try:
     from local_settings import *
except ImportError:
     pass

SQLALCHEMY_DATABASE_URI = DATABASE_URI_FMT.format(**
     {   'username': DB_USER,
         'password': DB_PASS,
         'hostname': DB_HOST,
         'port':     DB_PORT,
         'dbname':   DB_NAME,
         'schema':   DB_SCHEMA,
     })
#+end_src

    Where DB_USER, etc., are overridden from the top-level local_settings.py.

2) In my app factory (myApp/__init__.py, create_app()), I pull in
    myapp/default_settings.py via:

#+begin_src python
__all__ = ['create_app', 'db']
def create_app(name  __name__):
     app = Flask(name, static_path='/static')
     from app.config.from_object('myapp.default_settings')
     db.init_app(app)

     from myapp.bp.views import bp
     app.register_blueprint(bp)
     return app

db = SQLAlchemy()
#+end_src

3) Then wherever you need to call the db, you can import the db object and go
    to town.

#+begin_src python
from myapp import db
#+end_src

#+begin_src python
# bp/views.py
from flask import (Blueprint,)
from myapp import db
from .model import *

bp = Blueprint('bp', __name__, template_folder='templates')
@bp.route('/')
def index():
     return render_template('bp/index.html')
#+end_src

    And then in my models, for instance:

#+begin_src python
from sqlalchemy.dialects import postgresql
from sqlalchemy.sql import expression
from myapp import db

class FooClass(db.Model):
     __tablename__ = 'foo'
     __table_args__ = {'autoload':False, 'schema':'my_table_schema'}
     id = db.Column(db.Integer, primary_key=True)
     name = db.Column(postgresql.TEXT)

     @classmethod
     def foo_factory(self, var):
         """ Factory method that returns a valid Foo object if this query was
         successful. This is how I return results from a CTE query, btw. """
         return db.session.query(FooClass).from_statement('''SELECT id, 
name FROM foo WHERE some_crazy_expression = :var''').params(var_name = 
var)

# NoSQL = Wille E. Coyote. NoSQL = ~50 sec and 2:14 in to each of these
# episodes, respectively. http://www.youtube.com/watch?v=01cShwNkuMk
# http://www.youtube.com/watch?v=kvgADFXHajs
#+end_src

    That last foo_factory() is a *rediculously* handy trick for writing custom
    SQL and getting valid ORM objects back, but it took forever for me to
    figure that out. I don't use SQLA to generate my schema and advise against
    it in favor of always checking in your SQL create scripts.

#+begin_src shell
echo 'Hello World' >> myap/bp/templates/bp/index.html
#+end_src

4) Your file layout looks like:

#+begin_src
.git
local_settings.py
myapp/
myapp/__init__.py
myapp/bp/views.py
myapp/bp/model.py
myapp/bp/templates/bp/index.html
myapp/default_settings.py
#+end_src


-- 
Sean Chittenden

Re: [flask] declarative sqlalchemy

From:
Tom Borthwick
Date:
2011-11-07 @ 21:59
Thanks! I haven't tried blueprints yet but I'll check it out. That's
just what I was looking for.

On Sun, Nov 6, 2011 at 11:27 PM, Sean Chittenden <sean@chittenden.org> wrote:
> * Tom Borthwick <tborthwick@gmail.com> [2011-11-06 20:58:45 -0600]:
>
>>I'm just starting with python and this is more of a beginning
>>python/SqlAlchemy question, but following the declarative instructions
>>on http://flask.pocoo.org/docs/patterns/sqlalchemy/, what's the best
>>way to pass in the database uri rather than hard-code it? Is it really
>>a best practice to have the uri used in the global engine var or is
>>that just for demonstration?
>
> This should answer a few questions that have come up recently regarding
> templates, databases/SQLAlchemy and Blueprints.
>
> This is how I'm currently structuring apps now that we're in a
> post-Blueprints world. Figuring out this structure took a number of
> iterations, but it seems sane-enough now. -sc
>
>
> 1) I put a default SQLALCHEMY_DATABASE_URI string in
>    myapp/default_settings.py:
>
> #+begin_src python
> DATABASE_URI_FMT = 
'postgresql+psycopg2://{username}:{password}@{hostname}:{port}/{dbname}'
> DB_PASS = ''
> DB_PORT = '5432'
> DB_SCHEMA = 'initial_schema'
> DB_ADMIN = 'dba_role'
> DB_USER = 'app_user'
>
> from local_settings import *
> try:
>     from local_settings import *
> except ImportError:
>     pass
>
> SQLALCHEMY_DATABASE_URI = DATABASE_URI_FMT.format(**
>     {   'username': DB_USER,
>         'password': DB_PASS,
>         'hostname': DB_HOST,
>         'port':     DB_PORT,
>         'dbname':   DB_NAME,
>         'schema':   DB_SCHEMA,
>     })
> #+end_src
>
>    Where DB_USER, etc., are overridden from the top-level local_settings.py.
>
> 2) In my app factory (myApp/__init__.py, create_app()), I pull in
>    myapp/default_settings.py via:
>
> #+begin_src python
> __all__ = ['create_app', 'db']
> def create_app(name  __name__):
>     app = Flask(name, static_path='/static')
>     from app.config.from_object('myapp.default_settings')
>     db.init_app(app)
>
>     from myapp.bp.views import bp
>     app.register_blueprint(bp)
>     return app
>
> db = SQLAlchemy()
> #+end_src
>
> 3) Then wherever you need to call the db, you can import the db object and go
>    to town.
>
> #+begin_src python
> from myapp import db
> #+end_src
>
> #+begin_src python
> # bp/views.py
> from flask import (Blueprint,)
> from myapp import db
> from .model import *
>
> bp = Blueprint('bp', __name__, template_folder='templates')
> @bp.route('/')
> def index():
>     return render_template('bp/index.html')
> #+end_src
>
>    And then in my models, for instance:
>
> #+begin_src python
> from sqlalchemy.dialects import postgresql
> from sqlalchemy.sql import expression
> from myapp import db
>
> class FooClass(db.Model):
>     __tablename__ = 'foo'
>     __table_args__ = {'autoload':False, 'schema':'my_table_schema'}
>     id = db.Column(db.Integer, primary_key=True)
>     name = db.Column(postgresql.TEXT)
>
>     @classmethod
>     def foo_factory(self, var):
>         """ Factory method that returns a valid Foo object if this query was
>         successful. This is how I return results from a CTE query, btw. """
>         return db.session.query(FooClass).from_statement('''SELECT id, 
name FROM foo WHERE some_crazy_expression = :var''').params(var_name = 
var)
>
> # NoSQL = Wille E. Coyote. NoSQL = ~50 sec and 2:14 in to each of these
> # episodes, respectively. http://www.youtube.com/watch?v=01cShwNkuMk
> # http://www.youtube.com/watch?v=kvgADFXHajs
> #+end_src
>
>    That last foo_factory() is a *rediculously* handy trick for writing custom
>    SQL and getting valid ORM objects back, but it took forever for me to
>    figure that out. I don't use SQLA to generate my schema and advise against
>    it in favor of always checking in your SQL create scripts.
>
> #+begin_src shell
> echo 'Hello World' >> myap/bp/templates/bp/index.html
> #+end_src
>
> 4) Your file layout looks like:
>
> #+begin_src
> .git
> local_settings.py
> myapp/
> myapp/__init__.py
> myapp/bp/views.py
> myapp/bp/model.py
> myapp/bp/templates/bp/index.html
> myapp/default_settings.py
> #+end_src
>
>
> --
> Sean Chittenden
>