Metadata-Version: 2.1
Name: flask-sqlalchemy-unchained
Version: 0.7.5
Summary: Integrates SQLAlchemy Unchained with Flask
Home-page: UNKNOWN
Author: Brian Cappello
License: MIT
Description: # Flask SQLAlchemy Unchained
        
        Integrates [SQLAlchemy Unchained](https://github.com/briancappello/sqlalchemy-unchained) with [Flask](http://flask.pocoo.org/). This package is a very thin wrapper around [Flask-SQLAlchemy](http://flask-sqlalchemy.pocoo.org), and in terms of registering the extension with Flask, everything is the same.
        
        ## Basic Usage
        
        ```python
        # 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:
        
        ```bash
        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:
        
        ```python
        # app/autoapp.py
        
        import os
        
        from app.factory import create_app
        
        
        app = create_app(os.getenv('FLASK_ENV', 'development'))
        ```
        
        And now the app factory:
        
        ```python
        # 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:
        
        ```python
        # 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:
        ```
        
        ```python
        # app/extensions.py
        
        from flask_sqlalchemy_unchained import SQLAlchemyUnchained
        
        
        db = SQLAlchemyUnchained()
        ```
        
        The `User` model is the same as before:
        
        ```python
        # 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:
        
        ```python
        # 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.query(self.model).get(int(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:
        
        ```python
        # 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](https://flask-migrate.readthedocs.io/en/latest/) and [Py-YAML-Fixtures](https://py-yaml-fixtures.readthedocs.io/en/latest/), can be found [on GitHub](https://github.com/briancappello/sqlalchemy-demo).
        
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Requires-Python: >=3.5
Description-Content-Type: text/markdown
Provides-Extra: dev
Provides-Extra: docs
