Skip to main content

Flask SQLAlchemy Unchained

Integrates SQLAlchemy Unchained with Flask. This package is a very thin wrapper around Flask-SQLAlchemy, and in terms of registering the extension with Flask, everything is the same.

Basic Usage

# your_app.py

from flask import Flask
from flask_sqlalchemy_unchained import SQLAlchemyUnchained


app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
db = SQLAlchemyUnchained(app)


class User(db.Model):
    class Meta:
        repr = ('id', 'username', 'email')

    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

Now let's create the table and add a row:

export FLASK_APP='./your_app.py'
export FLASK_DEBUG='true'
flask shell
>>> from your_app import db, User
>>> db.create_all()
>>> user = User(username='fooar', email='foo@bar.com')
>>> db.session.add(user)
>>> db.session.commit()
>>> assert User.query.all() == [user]

Real-World Usage

Now let's take a look at using the application factory pattern. Our app's directory structure will look like this:

./your-project
├── app
│   ├── models
│   │   ├── __init__.py
│   │   └── user.py
│   ├── services
│   │   ├── __init__.py
│   │   ├── model_manager.py
│   │   └── user_manager.py
│   ├── __init__.py
│   ├── config.py
│   ├── extensions.py
│   └── factory.py
├── db
│   └── dev.sqlite
├── tests
│   ├── __init__.py
│   └── test_user.py
├── autoapp.py
└── setup.py

The entry point of our app will be autoapp.py, so let's take a look at that first:

# app/autoapp.py

import os

from app.factory import create_app


app = create_app(os.getenv('FLASK_ENV', 'development'))

And now the app factory:

# app/factory.py
from flask import Flask

from .config import DevConfig, ProdConfig, TestConfig
from .extensions import db


CONFIGS = {
    'development': DevConfig,
    'production': ProdConfig,
    'test': TestConfig,
}


def create_app(env):
    config = CONFIGS[env]

    app = Flask(__name__,
                template_folder=config.TEMPLATE_FOLDER,
                static_folder=config.STATIC_FOLDER,
                static_url_path=config.STATIC_URL_PATH)
    app.config.from_object(config)

    db.init_app(app)

    return app

Which leads us to the config and extensions modules:

# app/config.py

import os


class BaseConfig:
    DEBUG = os.getenv('FLASK_DEBUG', False)

    APP_ROOT = os.path.abspath(os.path.dirname(__file__))
    PROJECT_ROOT = os.path.abspath(os.path.join(APP_ROOT, os.pardir))

    SQLALCHEMY_TRACK_MODIFICATIONS = False


class DevConfig(BaseConfig):
    DEBUG = os.getenv('FLASK_DEBUG', True)

    db_path = os.path.join(BaseConfig.PROJECT_ROOT, 'db', 'dev.sqlite')
    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + db_path


class ProdConfig(BaseConfig):
    SQLALCHEMY_DATABASE_URI = \
        '{engine}://{user}:{password}@{host}:{port}/{db_name}'.format(
            engine='postgresql+psycopg2',
            user=os.getenv('FLASK_DATABASE_USER', 'sqlalchemy_demo'),
            password=os.getenv('FLASK_DATABASE_PASSWORD', 'sqlalchemy_demo'),
            host=os.getenv('FLASK_DATABASE_HOST', '127.0.0.1'),
            port=os.getenv('FLASK_DATABASE_PORT', 5432),
            db_name=os.getenv('FLASK_DATABASE_NAME', 'sqlalchemy_demo'))


class TestConfig(BaseConfig):
    TESTING = True
    DEBUG = True

    SQLALCHEMY_DATABASE_URI = 'sqlite://'  # :memory:
# app/extensions.py

from flask_sqlalchemy_unchained import SQLAlchemyUnchained


db = SQLAlchemyUnchained()

The User model is the same as before:

# app/models/user.py

from app.extensions import db


class User(db.Model):
    class Meta:
        repr = ('id', 'username', 'email')

    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

Because SQLAlchemy uses the data-mapper pattern, it's best practice to use managers/services for dealing with interactions with the database. A good base to start from might look like this:

# app/services/model_manager.py

from typing import *

from app.extensions import db


class ModelManager:
    model: Type[db.Model]

    def create(self, commit: bool = False, **kwargs) -> db.Model:
        instance = self.model(**kwargs)
        self.save(instance, commit)
        return instance

    def update(self, instance: db.Model, commit: bool = False,
               **kwargs) -> db.Model:
        for attr, value in kwargs.items():
            setattr(instance, attr, value)
        self.save(instance, commit)
        return instance

    def delete(self, instance: db.Model, commit: bool = False) -> None:
        db.session.delete(instance)
        if commit:
            self.commit()

    def save(self, instance: db.Model, commit: bool = True):
        db.session.add(instance)
        if commit:
            self.commit()

    def commit(self) -> None:
        db.session.commit()

    def rollback(self) -> None:
        db.session.rollback()

    def get(self, id) -> db.Model:
        return db.session.get(self.model, id)

    def get_by(self, **kwargs) -> db.Model:
        return db.session.query(self.model).filter_by(**kwargs).first()

    def find_all(self) -> List[db.Model]:
        return db.session.query(self.model).all()

    def find_by(self, **kwargs) -> List[db.Model]:
        return db.session.query(self.model).filter_by(**kwargs).all()

And then the UserManager class would look like this:

# app/services/user_manager.py

from ..models import User

from .model_manager import ModelManager


class UserManager(ModelManager):
    model = User

    def create(self, username, email, **kwargs) -> User:
        return super().create(username=username, email=email, **kwargs)


user_manager = UserManager()

The full source code for this example app, including integrations with Flask-Migrate and Py-YAML-Fixtures, can be found on GitHub.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flask_sqlalchemy_unchained-0.8.0.tar.gz (4.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flask_sqlalchemy_unchained-0.8.0-py3-none-any.whl (5.2 kB view details)

Uploaded Python 3

File details

Details for the file flask_sqlalchemy_unchained-0.8.0.tar.gz.

File metadata

  • Download URL: flask_sqlalchemy_unchained-0.8.0.tar.gz
  • Upload date:
  • Size: 4.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.6 Linux/6.6.6-arch1-1

File hashes

Hashes for flask_sqlalchemy_unchained-0.8.0.tar.gz
Algorithm Hash digest
SHA256 f47601f8b845ce4ae5e195ff816ab778ece4dd8b0dcfeaf5c87c4efbba091548
MD5 b3e062451a1d89b34d66396b2a860fda
BLAKE2b-256 e0587ff746e3a1b5576bfd85a0eefa7e9b567d801f96bff984c92920d591c154

See more details on using hashes here.

File details

Details for the file flask_sqlalchemy_unchained-0.8.0-py3-none-any.whl.

File metadata

File hashes

Hashes for flask_sqlalchemy_unchained-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e877543d60b6cfbbe321507df67be3b50e8754c5bfec6a1087ee17eb0dfbb555
MD5 1f2cb521891f75ecc081855fa0f679fb
BLAKE2b-256 1c56e013bde58b98774d98f71b6a9727b4e7f57a440ddc4a0911c1b8f646d28d

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.8.0 This release

2 files

0.7.6

2 files

0.7.5

2 files

0.7.4

2 files

0.7.3

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.9

2 files

0.6.8

2 files

0.6.7

2 files

0.6.6

2 files

0.6.5

2 files

0.6.4

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page