Re: [flask] How to use SQLAlchemy DB model from models.py in external
python script?
- From:
- Lucas Hrabovsky
- Date:
- 2011-02-25 @ 03:12
So say you have a models.py that looks like this:
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy
db = SQLAlchemy(current_app) #<--- Take note
meta = db.metadata
engine = db.engine
class Product(db.Model):
__tablename__ = 'products'
id = db.Column(db.Integer, primary_key=True)
slug = db.Column(db.String(255), nullable=False, unique=True)
name = db.Column(db.String(255), nullable=False, unique=True)
`current_app` will be your app if there is a request context. You have two
ways to make sure you have a request context and you dont get a nasty error.
One is the official way using app.test_request_context() as a context
manager:
from migrate.versioning.util import load_model
from migrate.versioning import genmodel, schemadiff, schema
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from app import app
with app.test_request_context():
from models import meta, db, engine, Product
try:
# managed upgrades
cschema = schema.ControlledSchema.create(engine, 'db_migrations')
cschema.update_db_from_model(meta)
except Exception, e:
print(e)
# unmanaged upgrades
diff = schemadiff.getDiffOfModelAgainstDatabase(meta, engine,
excludeTables=None)
genmodel.ModelGenerator(diff, engine).applyModel()
The other is kind of a hack i just made up that does something similar in
that its by no means a real request context but makes shit work in
standalone mode. Say you have an app.py that looks like this:
from flask import Flask, request, jsonify, render_template, make_response
def make_standalone(self):
"""Monkey patch so that we can have standalone scripts that dont
really need a request context, but have underlying modules which
rely on current_app as the primary use case."""
from werkzeug import create_environ
ctx = app.request_context(create_environ())
ctx.push()
Flask.make_standalone = make_standalone
app = Flask('flaskysqla')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.sqlite'
@app.route('/')
def index():
return render_template('index.html')
And then your migratedb looks like:
from migrate.versioning.util import load_model
from migrate.versioning import genmodel, schemadiff, schema
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from app import app
app.make_standalone() # <-- Use our BS request context.
from models import meta, db, engine, Product
try:
# managed upgrades
cschema = schema.ControlledSchema.create(engine, 'db_migrations')
cschema.update_db_from_model(meta)
except Exception, e:
print(e)
# unmanaged upgrades
diff = schemadiff.getDiffOfModelAgainstDatabase(meta, engine,
excludeTables=None)
genmodel.ModelGenerator(diff, engine).applyModel()
No context managers!
-Lucas
On Wed, Feb 23, 2011 at 6:11 PM, Alex <personxxl@gmail.com> wrote:
> Hello,
>
> I'm trying to use SQLAlchemy DB model in the external python script like
> this:
>
>
> =========== migratedb.py =======================
> from migrate.versioning.util import load_model
> from migrate.versioning import genmodel, schemadiff, schema
> from sqlalchemy import create_engine
> from sqlalchemy.ext.declarative import declarative_base
> from flask import Flask
> from flaskext.sqlalchemy import SQLAlchemy
> import losebit
> from losebit.models import db
>
> meta = db.metadata
> engine = db.engine
>
> try:
> # managed upgrades
> cschema = schema.ControlledSchema.create(engine, 'db_migrations')
> cschema.update_db_from_model(meta)
> except Exception, e:
> # unmanaged upgrades
> diff = schemadiff.getDiffOfModelAgainstDatabase(meta, engine,
> excludeTables=None)
> genmodel.ModelGenerator(diff, engine).applyModel()
> ======================================================
>
> For some reason db variable here is not initialized here with my DB model
> for some reason, I don't know how to initialize it right and this is the
> problem.
> When I copy-paste my model definition to migratedb.py it works fine, but
> when I do just "from losebit.models import db" It has no effect and I'm
> getting:
>
> ================================
> (env) C:\Users\Alex\Workspace\Python\flask>python migratedb.py
> Traceback (most recent call last):
> File "migratedb.py", line 19, in <module>
> engine = db.engine
> File
> "C:\Users\Alex\Workspace\Python\flask\env\lib\site-packages\flaskext\sqla
> lchemy.py", line 460, in engine
> raise RuntimeError('application not registered on db '
> RuntimeError: application not registered on db instance and no application
> bound
> ================================
>
> What do I do wrong?
>
> My app structure is:
> flask
> ``migratedb.py
> ``runserver.py
> ``losebit
> ````__init.py__
> ````models.py
>
>
>
> And when I copy paste all model definition to migratedb.py:
>
> ========== migratedb.py ==================
> from migrate.versioning.util import load_model
> from migrate.versioning import genmodel, schemadiff, schema
> from sqlalchemy import create_engine
> from sqlalchemy.ext.declarative import declarative_base
> from flask import Flask
> from flaskext.sqlalchemy import SQLAlchemy
> from losebit.models import *
>
> app = Flask(__name__)
> app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.sqlite'
>
> db = SQLAlchemy(app)
>
> meta = db.metadata
> engine = db.engine
>
> class Product(db.Model):
> __tablename__ = 'products'
> id = db.Column(db.Integer, primary_key=True)
> slug = db.Column(db.String(255), nullable=False, unique=True)
> name = db.Column(db.String(255), nullable=False, unique=True)
>
> try:
> # managed upgrades
> cschema = schema.ControlledSchema.create(engine, 'db_migrations')
> cschema.update_db_from_model(meta)
> except Exception, e:
> print(e)
> # unmanaged upgrades
> diff = schemadiff.getDiffOfModelAgainstDatabase(meta, engine,
> excludeTables=None)
> genmodel.ModelGenerator(diff, engine).applyModel()
> ================================
>
> Then it works fine, but I want just to import the model from "models.py"
> not to copy-paste it, how to do it?
>
> My other files:
>
> ========== losbit/__init__.py==========
> # -*- coding: utf-8 -*-
> from flask import Flask
> from flaskext.sqlalchemy import SQLAlchemy
> from losebit.views.frontend import frontend
> from losebit.views.admin import admin
> from models import db
>
> app = Flask(__name__)
> db.init_app(app)
>
> app.register_module(admin, url_prefix='/admin')
> app.register_module(frontend)
>
> app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.sqlite'
> #db = SQLAlchemy(app)
> =================================
>
> and
>
> ==========losebit/models.py==========
> # -*- coding: utf-8 -*-
> from flaskext.sqlalchemy import SQLAlchemy
> from datetime import datetime
> from sqlalchemy import Table, Column, Integer, Unicode, ForeignKey,
> DateTime
> from sqlalchemy.orm import mapper, relationship
> from sqlalchemy.sql.expression import *
>
> db = SQLAlchemy()
>
> class Product(db.Model):
> __tablename__ = 'products'
> id = db.Column(db.Integer, primary_key=True)
> slug = db.Column(db.String(255), nullable=False, unique=True)
> name = db.Column(db.String(255), nullable=False, unique=True)
> ================================
>
> Looks like I miss something simple with import and model initialization,
> can you point how to do it right?
>
> Thanks,
> Alex
>