diff --git a/uffd/__init__.py b/uffd/__init__.py index 55fa8360cce8fb3ee7b4355e9a258efd5b74386a..611f107c378286358dbd8506a93cc9d18e0da7d1 100644 --- a/uffd/__init__.py +++ b/uffd/__init__.py @@ -13,7 +13,7 @@ except ImportError: from werkzeug.exceptions import InternalServerError, Forbidden from flask_migrate import Migrate -from uffd.database import db, SQLAlchemyJSON +from uffd.database import db, SQLAlchemyJSON, customize_db_engine from uffd.template_helper import register_template_helper from uffd.navbar import setup_navbar from uffd.secure_redirect import secure_local_redirect @@ -79,6 +79,8 @@ def create_app(test_config=None): # pylint: disable=too-many-locals,too-many-sta db.init_app(app) Migrate(app, db, render_as_batch=True, directory=os.path.join(app.root_path, 'migrations')) + with app.app_context(): + customize_db_engine(db.engine) for module in [user, selfservice, role, mail, session, csrf, mfa, oauth2, services, rolemod, api, signup, invite]: for bp in module.bp: diff --git a/uffd/database.py b/uffd/database.py index 681581e19e4e17f1f113ad9bfe2e1ab7d25ed34a..68800c741860a3a3fb03eabba3da873506aaecb1 100644 --- a/uffd/database.py +++ b/uffd/database.py @@ -1,6 +1,6 @@ from collections import OrderedDict -from sqlalchemy import MetaData +from sqlalchemy import MetaData, event from flask_sqlalchemy import SQLAlchemy from flask.json import JSONEncoder @@ -15,6 +15,23 @@ metadata = MetaData(naming_convention=convention) db = SQLAlchemy(metadata=metadata) +def enable_sqlite_foreign_key_support(dbapi_connection, connection_record): + # pylint: disable=unused-argument + cursor = dbapi_connection.cursor() + cursor.execute('PRAGMA foreign_keys=ON') + cursor.close() + +# We want to enable SQLite foreign key support for app and test code, but not +# for migrations. +# The common way to add the handler to the Engine class (so it applies to all +# instances) would also affect the migrations. With flask_sqlalchemy v2.4 and +# newer we could overwrite SQLAlchemy.create_engine and add our handler there. +# However Debian Buster and Bullseye ship v2.1, so we do this here and call +# this function in create_app. +def customize_db_engine(engine): + if engine.name == 'sqlite': + event.listen(engine, 'connect', enable_sqlite_foreign_key_support) + class SQLAlchemyJSON(JSONEncoder): def default(self, o): if isinstance(o, db.Model):