From b181e544f49107bdb3696698ccb214b7910d70d0 Mon Sep 17 00:00:00 2001 From: e271828- Date: Wed, 23 Oct 2019 23:39:56 -0700 Subject: [PATCH 1/2] Add docs and example of using plain SQLAlchemy models with Flask-SQLAlchemy --- docs/models.rst | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/docs/models.rst b/docs/models.rst index 090ce031..f47aea8a 100644 --- a/docs/models.rst +++ b/docs/models.rst @@ -167,3 +167,82 @@ a query object using :meth:`Page.query.with_parent(some_tag) ` and then use it exactly as you would with the query object from a dynamic relationship. + +Using Plain SQLAlchemy Models +----------------------------- + +You may have pre-existing SQLAlchemy models that you would like to use +with Flask-SQLAlchemy, or conversely you may find yourself needing to access +the Flask-SQLAlchemy models you have already defined outside of a Flask context. + +The simplest method is to simply switch the base used for your models at run-time, +which will allow you to keep all of the convenience methods provided by Flask-SQLAlchemy. + +However, you are likely to find yourself wanting those methods if you are converting +pre-existing Flask-SQLAlchemy models to be accessible via plain SQLAlchemy. + +A complete worked example looks something like this: + + import os + from sqlalchemy import create_engine, Column, String, Integer + from sqlalchemy.ext.declarative import declarative_base + from sqlalchemy.orm import scoped_session, sessionmaker + from flask_sqlalchemy import SQLAlchemy + + # We can control this via `PLAIN_SQLALCHEMY_BASE=true python3 external_use.py` + PLAIN_SQLALCHEMY_BASE = "true" in os.getenv("PLAIN_SQLALCHEMY_BASE", "false").lower() + + if not PLAIN_SQLALCHEMY_BASE: + db = SQLAlchemy() + # Default flask-sqlalchemy base. + Base = db.Model + else: + # Standard sqlalchemy declarative base. + base = declarative_base() + + class Base(base): + __abstract__ = True + + # To maintain the same methods as flask-sqlalchemy, the following will work: + engine = create_engine() + session = sessionmaker(bind=engine) + db_session = scoped_session(session) + + # Enable `.query.` like flask-sqlalchemy. + Base.query = db_session.query_property() + + # Mock db.* to avoid altering methods on flask-sqlalchemy compatible models. + class dot_dict(dict): + def __getattr__(self, val): + return self[val] + + def drop_all(): + Base.metadata.drop_all(bind=engine) + + def create_all(): + Base.metadata.create_all(bind=engine) + + db = dot_dict({ + 'session': db_session, + 'drop_all': drop_all, + 'create_all': create_all, + 'mocked_obj': True + }) + + + # Example class with methods that can be used both inside and outside a flask context. + class User(Base): + __tablename__ = 'users' + user_id = Column(Integer, primary_key=True) + name = Column(String(255)) + + @staticmethod + def get_all(): + # This will continue to work without flask-sqlalchemy via the compatibility code. + return User.query.all() + + def delete(self): + # This will also work without flask-sqlalchemy via the compatibility code. + db.session.delete(self) + db.session.commit() + From 5bebe6e20cb145360aa9ccc427f2219293a6d50b Mon Sep 17 00:00:00 2001 From: e271828- Date: Wed, 23 Oct 2019 23:42:05 -0700 Subject: [PATCH 2/2] :: --- docs/models.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/models.rst b/docs/models.rst index f47aea8a..fb42a25a 100644 --- a/docs/models.rst +++ b/docs/models.rst @@ -181,7 +181,7 @@ which will allow you to keep all of the convenience methods provided by Flask-SQ However, you are likely to find yourself wanting those methods if you are converting pre-existing Flask-SQLAlchemy models to be accessible via plain SQLAlchemy. -A complete worked example looks something like this: +A complete worked example looks something like this:: import os from sqlalchemy import create_engine, Column, String, Integer @@ -229,7 +229,6 @@ A complete worked example looks something like this: 'mocked_obj': True }) - # Example class with methods that can be used both inside and outside a flask context. class User(Base): __tablename__ = 'users'