114

The quickstart tutorial for the Flask-SQLAlchemy plugin instructs users to create table models inheriting the db.Model class, e.g.

app = Flask(__main__)
db = SQLAlchemy(app)
class Users(db.Model):
    __tablename__ = 'users'
    ...

However, the SQLAlchemy tutorial and the bottle-SQLAlchemy README both suggest that table models inherit a Base instantiated from declarative_base().

Base = declarative_base()
class Users(Base):
    __tablename__ = 'users'
    ...

What is the difference between these two approaches?

davidism
  • 121,510
  • 29
  • 395
  • 339
drs
  • 5,679
  • 4
  • 42
  • 67

1 Answers1

118

Looking in the Flask-SQLAlchemy source code the db.Model class is initialized as follows:

self.Model = self.make_declarative_base()

And here is the make_declarative_base() method:

def make_declarative_base(self):
    """Creates the declarative base."""
    base = declarative_base(cls=Model, name='Model',
                            metaclass=_BoundDeclarativeMeta)
    base.query = _QueryProperty(self)
    return base

The _BoundDeclarativeMeta metaclass is a subclass of SQLAlchemy's DeclarativeMeta, it simply adds support for computing a default value for __tablename__ (the table name) and also to handle binds.

The base.query property enables Flask-SQLAlchemy based models to access a query object as Model.query instead of SQLAlchemy's session.query(Model).

The _QueryProperty query class is also subclassed from SQLAlchemy's query. The Flask-SQLAlchemy subclass adds three additional query methods that do not exist in SQLAlchemy: get_or_404(), first_or_404() and paginate().

I believe these are the only differences.

Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • 1
    I was just searching for this today for this app I've been building for a year or so, originally based off your "Mega Flask Tutorial," which uses db.Model rather than explicitly using Base = Declarative_Base. I got confused because my models all clearly use the Declarative extension but yet I had never called declarative_base(). Thanks for the great explanation! – Chockomonkey Jan 11 '16 at 22:15
  • Is it possible to use db.Model in one User Model and Base in Address Model. For example:- class User(db.Model), class Address(Base)? – Saif ali Karedia May 05 '17 at 13:42
  • Not sure, but my guess is that some things are not going to work. Flask-SQLAlchemy adds some behavior to the base in the `db.Model` class, so any models that inherit directly from the declarative base are not going to have that. – Miguel Grinberg May 05 '17 at 21:07
  • Can anyone still explain when to use which one and what are the benefits of declarative base? Also, how to add pagination in declarative base? – Karishma Sukhwani Aug 29 '22 at 08:11
  • @KarishmaSukhwani if you are using flask-sqlalchemy, use db.Model. if you are using sqlalchemy directly, use declarative_base. – Miguel Grinberg Aug 30 '22 at 09:06
  • I was using sqlalchemy within flask with declarative_base but some features like pagination was lagging and it was complicated to make another base class with mixin. so I moved back to flask-sqlalchemy now. Thanks. @MiguelGrinberg – Karishma Sukhwani Aug 30 '22 at 10:56
  • for anyone wondering, like me, the `metadata` you may be looking for is hiding under `db.metadata` – lababidi Mar 07 '23 at 20:42