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
- 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
pip install -r requirements.txt
make test
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
Multiple primary keys
To use some sort of identifier in the URI, the library tries to use the following logic.
- If a single primary key is found, use it! That was simple..
- For multiple keys, try to find a field with convention 'model_id'
- If not found, see if the model has 'pk_field' class variable
- 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
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/