Flask-SQLAlchemy

Arrested comes with built in support for working with Flask-SQLAlchemy. The SQLAlchemy mixins support automatically committing the database session when saving objects, filtering Queries by a model’s primary key when fetching single objects and the removal of objects from the database when deleting. Simply put, the SQLAlchemy mixin takes care of the boring stuff when integrating Arrested with SQLAlchemy.

Note

The referrence to Flask-SQLAlchemy does not strictly mean you can’t use vanilla SQLAlchemy with Arrested. See the section on providing access to the SQLAlchemy session object below for more information on custom configurations.

Usage

Let’s refactor the Characters resource from the quickstart example application to integrate with Flask-SQLAlchemy.

from arrested.contrib.sql_alchemy import DBListMixin, DBCreateMixin, DBObjectMixin

class CharacterMixin(object):

    response_handler = DBResponseHandler
    model = Character

    def get_query(self):

        stmt = db.session.query(Character)
        return stmt

class CharactersIndexEndpoint(Endpoint, DBListMixin, DBCreateMixin, CharacterMixin):

    name = 'list'
    many = True

    def get_response_handler_params(self, **params):

        params['serializer'] = character_serializer
        return params


class CharacterObjectEndpoint(Endpoint, DBObjectMixin, CharacterMixin):

    name = 'object'
    url = '/<string:obj_id>'

    def get_response_handler_params(self, **params):

        params['serializer'] = character_serializer
        return params

    def update_object(self, obj):

        data = self.request.data
        allowed_fields = ['name']

        for key, val in data.items():
            if key in allowed_fields:
                setattr(obj, key, val)

        return super(CharacterObjectEndpoint, self).update_object(obj)

We’ve managed to remove quite a bit of boilerplate code by using the DBMixins provided by the SQLAlchemy contrib module. We no longer need to add the objects to the session ourselves when creating or updating objects. We also removed the code from get_object that would return a 404 if the object was not found as the DBObjectMixin, by default, does this for us. Lastly, we removed the delete_object method as the DBObjectMixin takes care of this by default.

DBListMixin

The DBListMixin mixin implments the standard GetListMixin interface. We’d normally be required to implement the GetListMixin.get_objects method. DBListMixin handles this method and instead requires the get_query method. This method should return a Query object as opposed to a scalar Python type. DBListMixin will automatically call .all() on the Query object for you. If for some reason you need to handle this yourself you can overwrite the get_result method.

def get_query(self):

    return db.session.query(Character).all()

def get_result(self, query):

    if isinstance(query, list):
        return query
    else:
        return query.all()

DBObjectMixin

The DBListMixin mixin implements the ObjectMixin interface. It provides handling for GET, PATCH, PUT and DELETE requests for single objects in a single mixin. When implementing the DBObjectMixin interace we’d normally be required to implement the get_object method. Instead the DBObjectMixin requires the get_query method. This method should return a Query object opposed to a scalar Python type. DBObjectMixin will automatically apply a WHERE clause to filter the returned Query object by the primary key of the Endpoints model.

Filtering queries by id

The automatic filtering of the returned Query object can be configured using some class level attributes exposed by the DBObjectMixin class.

class CharacterObjectEndpoint(Endpoint, DBObjectMixin, CharacterMixin):

    name = 'object'
    url = '/<string:slug>'
    url_id_param = 'slug'
    model_id_param = 'slug'

    def get_response_handler_params(self, **params):

        params['serializer'] = character_serializer
        return params

    def update_object(self, obj):

        data = self.request.data
        allowed_fields = ['name']

        for key, val in data.items():
            if key in allowed_fields:
                setattr(obj, key, val)

        return super(CharacterObjectEndpoint, self).update_object(obj)

The model_id_param and url_id_param are used in conjunction to pull a custom kwarg from our url_mapping rule and then use it to filter a “slug” field on our model.

Cutom result handling

We can also control how DBObjectMixin converts the Query obejct returned by get_query into a scalar Python type using the get_result. By default, DBObjectMixin will call one_or_none() on the Query object returned.

def get_result(self, query):

    # We've already handled the query, just return it..
    return query

Custom Session configuration

Arrested assumes that you’re using SQLAlchemy with Flask. You can configure the DBMixins to work with other flavours of SQLAlchemy setup’s. By default Arrested will attempt to pull the SQLAlchemy db session from you Flask app’s configured extensions. The get_db_session method simply needs to return a valid SQLAlchemy session object.

def get_db_session(self):
    """Returns the session configured against the Flask appliction instance.
    """
    return my_session