# alto-django-utils

alto-django-utils is a set of convenient shortcuts for quickly setting up JSON HTTP APIs based on
django, DRF and dynamic-rest. The most important utility functions are:

- `alto_django_utils.serializers.serializer_for` and
- `alto_django_utils.viewsets.viewset_for`.

Both of these take the model class as the first argument (in addition to some optional ones) and
derive from it the serializer and viewset classes, needed to build up the API, with sensible defaults.
These can then be registered using `dynamic_rest.routers.DynamicRouter`.
The resulting API supports all the advanced features of dynamic-rest
(https://github.com/AltSchool/dynamic-rest) - complex filtering, ordering and sideloading of records
and their relations.

## Prerequisities
### install python

```bash
apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
  libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
  xz-utils # tk-dev

curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash

echo 'export PATH="/root/.pyenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"'               >> ~/.bash_profile
echo 'eval "$(pyenv virtualenv-init -)"'    >> ~/.bash_profile

source ~/.bash_profile

pyenv install 3.6.5
```

### create and activate virtualenv

```bash
pyenv virtualenv 3.6.5 tutor3.6.5
pyenv activate tutor3.6.5
```

### install django

```bash
pip install django
```

### create and enter project

```bash
django-admin startproject tutor
cd tutor
```

### add basic dependencies

```bash
echo django              >> requirements.in
echo django-extensions   >> requirements.in
echo djangorestframework >> requirements.in
echo dynamic-rest        >> requirements.in
echo '-e git+ssh://git@gitlab.alto-apps.mine.nu/python/alto-django-utils.git#egg=alto_django_utils' \
  >> requirements.in
```

### compile and install them

```bash
pip install pip-compile
pip-compile
pip install -r requirements.txt
```

### create app

```bash
django-admin startapp testapp
```

### register app in project

```python
# tutor/settings.py

INSTALLED_APPS = [
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
  'django_extensions',
  'rest_framework',
  'dynamic_rest',
  'testapp'
]
```

## Usage

### create first model

```python
# testapp/models.py

from django.db.models import Model, CharField, DateTimeField

class Client(Model):
  email      = CharField('Email',    max_length = 64)
  firstname  = CharField('Jméno',    max_length = 32)
  surname    = CharField('Příjmení', max_length = 32)
  created_at = DateTimeField(auto_now_add = True)
  updated_at = DateTimeField(auto_now = True)
```

### make and apply migration

```bash
./manage.py makemigrations -n create_client
./manage.py migrate
```

### create serializer

```python
# testapp/serializers.py

from alto_django_utils.serializers import serializer_for
from .models import Client

ClientSerializer = serializer_for(Client)
```

### create viewset

```python
# testapp/viewsets.py

from alto_django_utils.viewsets import viewset_for
from .models      import Client
from .serializers import ClientSerializer

ClientViewSet = viewset_for(Client, ClientSerializer)
```

### register viewset in app urls

```python
# testapp/urls.py

from django.conf.urls import url, include
from dynamic_rest.routers import DynamicRouter
from .viewsets import ClientViewSet

crud_router = DynamicRouter()

crud_router.register_resource(ClientViewSet)

app_name    = 'testapp'
urlpatterns = [
  url(r'^crud/', include(crud_router.urls)),
]
```

### include app urls in project urls

```python
# tutor/urls.py

from django.conf.urls import url, include

urlpatterns = [
  url(r'^test/', include('testapp.urls')),
]
```

### list created urls

```bash
./manage.py show_urls
# /test/crud/clients/        views.ClientViewSet   testapp:clients-list
# /test/crud/clients/<pk>/   views.ClientViewSet   testapp:clients-detail
```

### test created urls

```bash
./manage.py runserver # in separate shell

pip install httpie

http post :8000/test/crud/clients firstname=Testy surname=Testson email=test@test.cz
http get  :8000/test/crud/clients?filter{firstname.icontains}=test
# {
#     "count": 1,
#     "next": null,
#     "previous": null,
#     "results": {
#         "clients": [
#             {
#                 "id": 1,
#                 "email": "test@test.cz",
#                 "firstname": "Testy",
#                 "surname": "Testson",
#                 "created_at": "2018-04-19T03:02:16.850640Z",
#                 "updated_at": "2018-04-19T03:02:16.850786Z"
#             }
#         ]
#     }
# }
```

### get more info at https://github.com/AltSchool/dynamic-rest
