11

I am using Flask for my python wsgi server, and sqlalchemy for all my database access.

I think I would like to use the Flask-Sqlalchemy extension in my application, but I do not want to use the declarative base class (db.Model), instead, I want to use the base from sqlalchemy.ext.declarative.

Does this defeat the entire purpose of using the extension?


My use case:

I would like the extension to help me manage sessions/engines a little better, but I would like to handle all models separately.

I actually wouldn't mind using the extension, but I want to write strict models. I am porting code from a non-flask application, and I will be pushing changes back to that project as I go. If flask-sqlalchemy allows me to cheat on Table metadata for instance, that is going to cause problems when the code is pushed back out. There are also portions of my code that do lots of type checking (polymorphic identities), and I also remember reading that type checking on Table is not recommended when using the extension.

3 Answers 3

9

You can have Flask-SQLAlchemy expose your own base Model instead of it's built-in one. Just subclass SQLAlchemy and override make_declarative_base.

from flask.ext.sqlalchemy import SQLAlchemy


class CustomAlchemy(SQLAlchemy):
    def make_declarative_base(self):
        base = declarative_base(...)
        ...
        return base

db = CustomAlchemy()
Sign up to request clarification or add additional context in comments.

Comments

1

I'm actually using sqlalchemy in flask without using declarative base and I don't have any problems. You can always do that if you want to, there is no obligation to use object relational mapper, ORM is just one part of sqlalchemy. You can always just stay with alchemy sql expression language, define your tables in model objects, and define some methods there that will use expression language. I have a code like this (Model is the object i defined earlier), connect is a decorator which connects to db, it works fine for me.

def connect(func):
    eng = create_engine(app.config["DATABASE"])
    @wraps(func)
    def wrapped(*args,**kwargs):
        with closing(eng.connect()) as con:
            result = con.execute(func(*args,**kwargs))
        return result
    return wrapped

class User_(Model):
    def __init__(self):
        Model.__init__(self)
        self.metadata = MetaData()
        self.structure = Table("users", self.metadata,
                               Column("id",Integer,primary_key=True),
                               Column("username",VARCHAR(64)),
                               Column("password",TEXT),
                               Column("email",VARCHAR(100)),
                               Column("about_me",TEXT),
                               Column("deadline",DATETIME),
                               Column("points",INTEGER)),
                               Column("date_created",DATETIME))

    @connect
    def get_hashed_pass(self,username):
        """  """
        t = self.structure
        s = select([t.c.password]).where(t.c.username == str(username))
        return s
 #other methods follow

Flask's documentation concerning alchemy explicitly says that it is completely okay to do that:

If you just want to use the database system (and SQL) abstraction layer you basically only need the engine

P.S. Oh, and one more thing, they say in the docs that if you want to get started quickly you're better off using extension, but I'm personally not so sure about that, if you're like me and you feel more familiar with the sql queries rather then with ORM, it may be much easier for you to get started quickly without extension.

1 Comment

It took me a while to get your meaning (I didn't see the connect decorator on the method). Using a session inside of a model was going to be my next question!
0

SQLAlchemy themselves actually recommend you use the Flask wrapper (db.Model) for Flask projects. That being said I have used the declarative_base model in several of my Flask projects where it made more sense.

It does defeat the whole purpose of the SQLAlchemy class from flask-sqlalchemy.

Here's some sample code:

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
import datetime

#set up sqlalchemy
engine = create_engine('postgresql://<username>:<password>@localhost/flask_database')
Base = declarative_base()
metadata = Base.metadata
metadata.bind = engine
Session = sessionmaker(bind=engine, autoflush=True)
session = Session()


class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    api_owner_id = Column(Integer, ForeignKey('api.id'))
    email = Column(String(120), unique=True)
    username = Column(String(120), unique=True)
    first_name = Column(String(120))
    last_name = Column(String(120))
    business_name = Column(String(120))
    account_type = Column(String(60))
    mobile_phone = Column(String(120))
    street = Column(String(120))
    street2 = Column(String(120))
    city = Column(String(120))
    state = Column(String(120))
    zip_code = Column(String(120))
    country = Column(String(120))
    creation_date = Column(DateTime, default=datetime.datetime.now())
    password = Column(String(120))
    #github stuffs
    github_link = Column(Boolean, default=False)
    github_usn = Column(String(120))
    github_oauth_token = Column(String(160))
    #balanced stuffs
    balanced_account_uri = Column(String(120))
    ach_verified = Column(Boolean, default=False)
    active = Column(Boolean, default=True)
    profile_updated = Column(Boolean, default=False)
    account_balance = Column(Numeric(precision=10, scale=2), default=0.00)
    admin = Column(Boolean, default=False)
    devapp = relationship('DevApp', backref="user", lazy="dynamic")
    projects = relationship('Project', backref="user", lazy="dynamic")
    proposals = relationship('Proposal', backref="user", lazy="dynamic")
    transactions = relationship('Monies', backref="user", lazy="dynamic")

    def __repr__(self):
        return self.email

4 Comments

Your session/engine bit helped illustrate your answer. So, in my flask app, I need to pass around the session for usage. Do I need to clean up the session in any way after each use? (Maybe using app.do_teardown_xxx?)
With the autoflush=True param in sessionmaker no cleanup is needed. user = User(email="[email protected]") session.add(user) session.commit()
I don't plan to run this across multiple threads, but I will have discrete modules each using their own new session. I am planning to pass the sessionmaker. Those modules will make progressive updates. After committing each session instance, should there be any reason to worry about data integrity? (assuming my commits don't clobber each other).
I'm pretty sure you'll have no issue with sessions clobbering eachother as long as each has it's own database connection. But I am not entirely sure so I would ask another question if it's a concern. Best

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.