pallets-eco / flask-session

Server side session extension for Flask
https://flask-session.readthedocs.io
BSD 3-Clause "New" or "Revised" License
488 stars 236 forks source link

A 'SQLAlchemy' instance has already been registered on this Flask app #215

Closed hexkey closed 3 months ago

hexkey commented 4 months ago

Per my understanding, and I might be wrong but, It seems that there is an attempt to initialize a new SQLAlchemy instance with the Flask application in the Flask-Session setup process, even though an instance has already been initialized. Thanks for any feedback.

flask | File "/usr/local/lib/python3.11/site-packages/flask_session/init.py", line 122, in _get_interface flask | session_interface = SqlAlchemySessionInterface( flask | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ flask | File "/usr/local/lib/python3.11/site-packages/flask_session/sessions.py", line 584, in init flask | db = SQLAlchemy(app) flask | ^^^^^^^^^^^^^^^ flask | File "/usr/local/lib/python3.11/site-packages/flask_sqlalchemy/extension.py", line 278, in init flask | self.init_app(app) flask | File "/usr/local/lib/python3.11/site-packages/flask_sqlalchemy/extension.py", line 312, in init_app flask | raise RuntimeError( flask | RuntimeError: A 'SQLAlchemy' instance has already been registered on this Flask app. Import and use that instance instead.

FILE: config.py class Config(Config): SQLALCHEMY_BINDS = { "db1": f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:5432/db1", "db2": f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:5432/db2", }

SESSION_TYPE = "sqlalchemy"
SESSION_SQLALCHEMY_BIND_KEY = "db1"
SESSION_SQLALCHEMY_TABLE = "sessions"

FILE: init.py from database.db import db from flask import session from flask_session import Session

sess = Session()

def create_app(config=None): app = Flask(name) app.config.from_object(Config) db.init_app(app) sess.init_app(app)

return app, celery

FILE database.py: from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def init_app(app): db.init_app(app)

Lxstr commented 4 months ago

You can pass SESSION_SQLALCHEMY = db

hexkey commented 4 months ago

sqlalchemy.exc.UnboundExecutionError: 'SQLALCHEMY_DATABASE_URI' config is not set. Bind key 'None' is not in 'SQLALCHEMY_BINDS' config.

Lxstr commented 4 months ago

Those are SQLAlchemy configs, unrelated to flask session. All we care is that you pass a valid SQLAlchemy instance to SESSION_SQLALCHEMY. Can you provide each file using code blocks with three backtics ``` above and below each code. Did you have SQLAlchemy working priior to adding sessions?

Lxstr commented 4 months ago

Try this order:


app = Flask(__name__)
app.config.from_object(__name__)
app.config.update(
    {
        "SQLALCHEMY_DATABASE_URI": "sqlite:////tmp/test.db",
    }
)
db = SQLAlchemy()
db.init_app(app)
app.config.update(
    {
        "SESSION_SQLALCHEMY": db,
        "SESSION_TYPE": "sqlalchemy",
    }
)
Session(app)
hexkey commented 4 months ago

Thank you. But I can't use this approach as I am using create_app app factory function, and I would like to initialize Session same way like I initialize other modules, via init_app(app) call:

sess = Session()
sess.init_app(app)

I can't remove SQLALCHEMY_BINDS as this would break the whole app. To answer your question SQLAlchemy work just fine prior to adding sessions. I am struggling with SQLALCHEMY_BINDS configuration for Session, and if you have any ideas how to solve this I would very much appreciate it.

Lxstr commented 4 months ago

No problem if you want to use app factory, should not make a difference. Can you do a single file minimum reproducible example for me? Just one simplified file app.py that I can run and try. Also, I have just released 0.7.0rc1 that may make a difference.

hexkey commented 4 months ago

Hello Lxstr, thanks for being responsive and helpful.

In this repo you can easily test this setup: https://github.com/hexkey/flask-sessions-testing

Let me know if I can help with anything else from my side.

Lxstr commented 3 months ago

Hi @hexkey thanks for the excellent reproduction. I've released 0.7.0rc2 with fixed for bind keys, however you also need to either delete db.init_app(app) or add directly below it app.config["SESSION_SQLALCHEMY"] = db

Either this:

from flask_session import Session

from app.config import Config
from app.database.db import db
from flask import Flask

sess = Session()

def create_app():
    app = Flask(__name__)

    app.config.from_object(Config)
    db.init_app(app)
    app.config["SESSION_SQLALCHEMY"] = db

    sess.init_app(app)

    from app.guest.routes import guest

    app.register_blueprint(guest)

    return app

Or this:

from flask_session import Session

from app.config import Config
from app.database.db import db
from flask import Flask

sess = Session()

def create_app():
    app = Flask(__name__)

    app.config.from_object(Config)

    sess.init_app(app)

    from app.guest.routes import guest

    app.register_blueprint(guest)

    return app

In the second case flask-session will create it's own instance.

Lxstr commented 3 months ago

Let me know if you have any issues