fictive.sqlalchemy package

Subpackages

fictive.sqlalchemy.ext

fictive.sqlalchemy.framework

Framework compponents for sharing SQLAlchemy metadata between packages and projects

Submodules

fictive.sqlalchemy.types

Custom SQLAlchemy column types

Module contents

Fictive Kin library for using SQLAlchemy

class fictive.sqlalchemy.FindOrCreateDescriptor(session_factory)[source]

Bases: object

Descriptor for attaching a find_or_create method to a model class

from fictive.sqlalchemy import FindOrCreateDescriptor

class Model(DeclarativeBase):
    __tablename__ = 'model'
    id = Column(Integer, primary_key=True)
    value = Column(String)

    find_or_create = FindOrCreateDescriptor(session_factory)

DeclarativeBase.metadata.create_all(engine)
>>> created = Model.find_or_create(value='created')
>>> session.add(created)
>>> session.commit()
>>> (created.id, created.value)
(1, 'created')
>>> retrieved = Model.find_or_create(value='created')
>>> (retrieved.id, retrieved.value)
(1, 'created')
>>> # each call to find_or_create falls the session_factory so
>>> # the instances may be in different sessions unless the
>>> # factory returns the same session over multiple calls
>>> # (e.g., `sqlalchemy.orm.scoping.scoped_session`)
>>> retrieved is created
False
__init__(session_factory)[source]

Initialize self. See help(type(self)) for accurate signature.

class fictive.sqlalchemy.ModelDescriptor(model: str, base: sqlalchemy.ext.declarative.api.DeclarativeMeta)[source]

Bases: object

Lazy reference to a declarative_base subclass

In large applications, “models” are often declared in separate files from each other and from “controllers” or “views” that utilize the models. This can easily lead to “circular import” issues in Python that can require substantial refactoring or subtle non-idiomatc hacks of Python’s import behavior.

SQLAlchemy provides some features that can alleviate this concern, most notably the Declarative extension that, among other features, allows strings to be used in place of class references. E.g.:

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship

from application.models import Base

class ChildModel(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(ForeignKey('parent.id'))
    #: We don't need to `from parents import ParentModel`
    #: here; the string reference will be resolved at run time
    parent = relationship('ParentModel')

This descriptor uses the Declarative extension to wrap a string reference to a declarative_base subclass (i.e., a model class) in a generalized way. When the owning class calls the __get__ method, the descriptor will automatically dereference the string reference and return the indicated declarative_base subclass. E.g.:

class MyController(object):
    #: We don't need to `from models import ExampleModel`
    #: here; the string reference will be resolved at run time
    model_class = ModelDescriptor('ExampleModel', Base)

    def describe_model(self):
        return self.model_class.__tablename__
>>> MyController().describe_model()
'example_model_table'
__init__(model: str, base: sqlalchemy.ext.declarative.api.DeclarativeMeta)[source]
Parameters
fictive.sqlalchemy.find_or_create(session: sqlalchemy.orm.session.Session, model_class: sqlalchemy.ext.declarative.api.DeclarativeMeta, **kwargs)[source]

retrieves an instance from the database or creates one if it doesn’t exist

E.g.:

from sqlalchemy import Column, Integer, String
from fictive.sqlalchemy import find_or_create

class Model(DeclarativeBase):
    __tablename__ = 'model'
    id = Column(Integer, primary_key=True)
    value = Column(String)

DeclarativeBase.metadata.create_all(engine)
>>> first = Model(value='first')
>>> session.add(first)
>>> session.commit()
>>> found = find_or_create(session, Model, value='first')
>>> (found.id, found.value)
(1, 'first')
>>> found is first
True
>>> created = find_or_create(session, Model, value='second')
>>> (created.id, created.value)
(None, 'second')
>>> created in session
False
Parameters