Library to integrate Django REST Framework and SQLAlchemy
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
djangorest_alchemy
docs
examples
.gitignore
.importanizerc drf3 changes with test case changes Jun 30, 2015
.travis.yml
AUTHORS.rst added myself to contributors list Jul 8, 2015
CONTRIBUTING.rst
HISTORY.rst Updated version, added release notes, fixed flake9 violations Jul 14, 2015
LICENSE Updated to use MIT license May 5, 2014
MANIFEST.in Added requirements.txt in manifest for dep install Oct 15, 2014
Makefile Changes per standards Aug 21, 2014
README.md
README.rst Updates to README May 14, 2014
requirements.txt
setup.cfg Use awesome cookiecutter project May 5, 2014
setup.py
tox.ini

README.md

djangorest-alchemy

A library to integrate the awesome frameworks Django REST Framework and SQLAlchemy

  • Free software: MIT license
  • Supports SQLAlchemy 0.7.8 and above
  • Tested with Django 1.4

Features

  • Provides GET verb implementation for SQLAlchemy models
  • List, filter and paginate multiple rows
  • Fetch single object with nested objects as complete URIs
  • Supports multiple primary keys
  • Provides ability to use 'Manager' like classes to work with SQLAlchemy models
  • Supports both Declarative and Classical styles

Install dependencies

pip install -r requirements.txt

Run tests

make test

Usage

Getting Started

Assuming you have a SQLAlchemy model defined as below::

class DeclarativeModel(Base):
    __tablename__ = 'test_model'

    declarativemodel_id = Column(INTEGER, primary_key=True)
    field = Column(String)
    datetime = Column(DateTime, default=datetime.datetime.utcnow)
    floatfield = Column(Float)
    bigintfield = Column(BigInteger)
    child_model = relationship(ChildModel, uselist=False, primaryjoin=
                              (declarativemodel_id == ChildModel.parent_id))

Define the 'manager' class to work on above model::

class DeclarativeModelManager(SessionMixin, AlchemyModelManager):
    model_class = DeclarativeModel

SessionMixin just provides a convenient way to initialize the SQLAlchemy session. You can achieve the same by definining init and setting self.session instance

Define the Django REST viewset and specify the manager class::

class DeclModelViewSet(AlchemyModelViewSet):
    manager_class = DeclarativeModelManager

Finally, register the routers as you would normally do using Django REST::

viewset_router = routers.SimpleRouter()
viewset_router.register(r'api/declmodels', DeclModelViewSet,
                        base_name='test-decl')

Pagination

Pagination works exactly like Django REST Framework (and Django). Provided your viewset has the paginate_by field set, pass page number in querystring::

    class ModelViewSet(AlchemyModelViewSet):
        paginate_by = 25
  • 5th page curl -v http://server/api/declmodels/?page=5
  • Last page curl -v http://server/api/declmodels/?page=last
  • First page curl -v http://server/api/declmodels/

Filters

Filters work exactly like Django REST Framework. Pass the field value pair in querystring.

curl -v http://server/api/declmodels/?field=value

Advanced Usage

Multiple primary keys

To use some sort of identifier in the URI, the library tries to use the following logic.

  1. If a single primary key is found, use it! That was simple..
  2. For multiple keys, try to find a field with convention 'model_id'
  3. If not found, see if the model has 'pk_field' class variable
  4. If not found, raise KeyNotFoundException

In addition, to support multiple primary keys which cannot be accomodated in the URI, the viewset needs to override the get_other_pks method and return back dictionary of primary keys. Example::

class ModelViewSet(AlchemyModelViewSet):
    manager_class = ModelManager
    def get_other_pks(self, request):
        pks = {
            'pk1': request.META.get('PK1'),
            'pk2': request.META.get('PK2'),
        }
        return pks

Manager factory

The base AlchemyModelViewSet viewset provides a way to override the instantiation of the manager. Example::

class ModelViewSet(AlchemyModelViewSet):
    def manager_factory(self, *args, **kwargs):
        return ModelManager()

Nested Models

This library recommends using the drf-nested-routers for implementing nested child models. Example::

child_router = routers.NestedSimpleRouter(viewset_router, r'api/declmodels',
                                      lookup='declmodels')

For more details, refer to the drf-nested-routers documentation.

Custom methods

DRF allows to add custom methods other than the default list, retrieve, create, update and destroy using the @action decorator. However, if you have managers, then you can simply provide action methods on the manager and specify the action methods using action_methods field The methods have to return back appropriate status per below map.

STATUS_CODES = {
    'created': status.HTTP_201_CREATED,
    'updated': status.HTTP_200_OK,
    'accepted': status.HTTP_202_ACCEPTED
}


class MyManager(AlchemyModelManager):
    action_methods = {'do_something': ['POST']}

    def do_something(self, data, pk=None, **kwargs):
        # data is actual payload
        return {'status': 'created'}

class ModelViewSet(AlchemyModelViewSet):
        manager_class = MyManager

curl -X POST http://server/api/declmodels/1/do_something/

Read-only API

If you need only the GET method, and do not wish to expose/support POST/PUT/DELETE then you can use the djangorest_alchemy.routers.ReadOnlyRouter instead of the DefaultRouter

Examples

The examples folder demonstrates a real-world example using Cars and Parts as the object models.

Run the following command just as you would normally run a Django project:

cd examples
python manage.py runserver --settings=settings

Then type the following in your favorite browser:

http://localhost/api/cars/