26

I had a small web service built using Flask and Flask-SQLAlchemy that only held one model. I now want to use the same database, but with a command line app, so I'd like to drop the Flask dependency.

My model looks like this:

class IPEntry(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    ip_address = db.Column(db.String(16), unique=True)
    first_seen = db.Column(db.DateTime(),
        default = datetime.datetime.utcnow
    )
    last_seen = db.Column(db.DateTime(),
        default = datetime.datetime.utcnow
    )

    @validates('ip')
    def validate_ip(self, key, ip):
        assert is_ip_addr(ip)
        return ip

Since db will no longer be a reference to flask.ext.sqlalchemy.SQLAlchemy(app), how can I convert my model to use just SQLAlchemy. Is there a way for the two applications (one with Flask-SQLAlchemy the other with SQLAlchemy) to use the same database?

3
  • The database should be independent of the models or ORM layer you're using. Commented May 8, 2015 at 3:06
  • 4
    Yeah, I get that. I'm looking for a way to reuse code in both flask and non flask without having to change my model definitions in any significant way. Commented May 8, 2015 at 3:16
  • There's nothing flask-related in your model. All you need is to create a db connection and import your model to either flask, or non-flask app. I'd simply put the model in 'models.py' so (really just move the above from the flask main .py file and import/instantiate IPentry when needed). Commented May 9, 2015 at 4:00

8 Answers 8

12

you can do this to replace db.Model:

from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base
import sqlalchemy as sa

base = declarative_base()
engine = sa.create_engine(YOUR_DB_URI)
base.metadata.bind = engine
session = orm.scoped_session(orm.sessionmaker())(bind=engine)

# after this:
# base == db.Model
# session == db.session
# other db.* values are in sa.*
# ie: old: db.Column(db.Integer,db.ForeignKey('s.id'))
#     new: sa.Column(sa.Integer,sa.ForeignKey('s.id'))
# except relationship, and backref, those are in orm
# ie: orm.relationship, orm.backref
# so to define a simple model

class UserModel(base):
    __tablename__ = 'users' #<- must declare name for db table
    id = sa.Column(sa.Integer,primary_key=True)
    name = sa.Column(sa.String(255),nullable=False)

then to create the tables:

 base.metadata.create_all()
Sign up to request clarification or add additional context in comments.

Comments

5

That is how to use SQLAlchemy without Flask (for example to write a bulk of objects to PostgreSQL database):

from sqlalchemy import Column, Integer, String
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# Define variables DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, DB_NAME   
SQLALCHEMY_DATABASE_URI = f'postgresql://{DB_USERNAME}:{DB_PASSWORD}@{DB_HOST}: 
{DB_PORT}/{DB_NAME}'

# ----- This is related code -----
engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=True)
Base = declarative_base()
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
Session.configure(bind=engine)
session = Session()
# ----- This is related code -----

class MyModel(Base):
    __tablename__ = 'my_table_name'

    id = Column(Integer, primary_key=True)
    value = Column(String)

objects = [MyModel(id=0, value='a'), MyModel(id=1, value='b')]
session.bulk_save_objects(objects)
session.commit()

2 Comments

I don’t think the question was related to bulk inserts
@KyleRoux bulk insert is just a simple example to make a reproducible code. The related part is 6 lines on top where I create an engine. I spent quite a lot of time to make it working without Flask this way, so not sure why you think it is not relevant :/
3

Check this one github.com/mardix/active-alchemy

Active-Alchemy is a framework agnostic wrapper for SQLAlchemy that makes it really easy to use by implementing a simple active record like api, while it still uses the db.session underneath. Inspired by Flask-SQLAlchemy

1 Comment

Wow, this wrapper was worked perfectly for my models. Thank you for the suggestion!
1

This does not completely answer your question, because it does not remove Flask dependency, but you can use SqlAlchemy in scripts and tests by just not running the Flask app.

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData

test_app = Flask('test_app')
test_app.config['SQLALCHEMY_DATABASE_URI'] = 'database_uri'
test_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

metadata = MetaData(schema='myschema')
db = SQLAlchemy(test_app, metadata=metadata)

class IPEntry(db.Model):
    pass

One difficulty you may encounter is the requirement of using db.Model as a base class for your models if you want to target the web app and independent scripts using same codebase. Possible way to tackle it is using dynamic polymorphism and wrap the class definition in a function.

def get_ipentry(db):
    class IPEntry(db.Model):
        pass
    return IPEntry

As you construct the class run-time in the function, you can pass in different SqlAlchemy instances. Only downside is that you need to call the function to construct the class before using it.

db = SqlAlchemy(...)
IpEntry = get_ipentry(db)
IpEntry.query.filter_by(id=123).one()

Comments

1

There is a great article about Flask-SQLAlchemy: how it works, and how to modify models to use them outside of Flask:

http://derrickgilland.com/posts/demystifying-flask-sqlalchemy/

1 Comment

This is a great link but is currently broken/down. web.archive.org/web/20190530064812/http://derrickgilland.com/… can help
1

The sqlalchemy docs has a good tutorial with examples that sound like what you want to do.

Shows how to connect to a db, mapping, schema creation, and querying/saving to the db.

1 Comment

Should update the link though... docs.sqlalchemy.org/en/latest/orm/tutorial.html
0

Flask (> 1.0) attempt to provide helpers for sharing code between an web application and a command line interface; i personally think it might be cleaner, lighter and easier to build libraries unbound to flask, but you might want to check:

4 Comments

Both these links currently appear to be broken.
@holdenweb < links to the official documentation fixed, thank you for reporting
They're down again.
flask.palletsprojects.com/en/latest/cli takes out the version so it should work as long as cli is supported...
0

Create database and table

import os

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

if os.path.exists('test.db'):
    os.remove('test.db')

Base = declarative_base()


class Person(Base):
    __tablename__ = 'person'

    id = Column(Integer(), primary_key=True)
    name = Column(String())


engine = create_engine('sqlite:///test.db')
Base.metadata.create_all(engine)

Using Flask_SQLAlchemy directly

from flask import Flask
from sqlalchemy import MetaData
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String

app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app, metadata=MetaData())


class Person(db.Model):
    __tablename__ = 'person'

    id = Column(Integer(), primary_key=True)
    name = Column(String())


person = Person(name='Bob')
db.session.add(person)
db.session.commit()
print(person.id)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.