Skip to main content

Customized features and environment for building a Django REST framework app.

Project description

Django REST base

Customized features and environment for building a Django REST framework app.

Requirements

  • Python 3.8
  • Django 3.0
  • djangorestframework (Django REST framework)

Optional packages required for additional features.

  • PyJWT TokenAuthentication
  • channels NullURLRouter, NullConsumer
  • sentry-sdk sentry_report (when Sentry reports enabled)
  • numpy rest_base.utils.random

Installation

pip install django-rest-base

settings.py

INSTALLED_APPS = [
    ...,
    'rest_base',
]

Features

Error

settings.py

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_base.errors.exception_handler',
}

errors.py

from rest_base.errors import Error

MyAppError = Error('my_app')  # class

MyError = MyAppError('My', 'Error')  # class
MyErrorInstance = MyError(detail='caution: this is instance!')  # instance (when *args and code not provided)

views.py

from my_app.errors import MyError, MyErrorInstance

def my_view(request):
    raise MyError(detail='Something went wrong :(')

def another_view1(request):
    raise MyError  # raise without parameters is also permitted

def another_view2(request):
    raise MyErrorInstance()  # __call__ should be used to raise instance

rest_base.errors.exception_handler is similar with REST framework's default handler, but provides advanced error format.

In Django REST base environment, every exception from views inherits rest_base.errors.Error. Even original REST framework's exceptions and unhandled exceptions will be converted to Error.

Those Errors will generate Response which has following error format.

{
  "error": {
    "code": "My::Error",
    "detail": "Something went wrong :(",
    "traceback": "(traceback)"
  }
}

detail and traceback are optional, and traceback will be included automatically when Django's DEBUG mode is enabled.

View

urls.py

from django.urls import re_path

from rest_base.urls import method_branch
from . import views

urlpatterns = [
    re_path(r'^my_endpoint/?$', method_branch(GET=views.my_view, POST=views.another_view)),
]

rest_base.urls.method_branch branch the requests by it's method—GET, POST, PUT, DELETE. It also supports @rest_framework.decorators.authentication_classes and @rest_framework.decorators.permission_classes for each view.

Model

models.py

from rest_base.models import BaseModel, BaseUser, BaseToken, semaphore

@semaphore(block=True)
class MyModel(BaseModel):
    field = ...

class MyUser(BaseUser):
    field = ...

class MyToken(BaseToken):
    field = ...

By replacing the original Django models.Model with rest_base.models.BaseModel, several customized features can be used.

  • created, last_modified fields
  • objects.update_or_create updates instance only if original attributes and defaults are not same.
  • bulk_manager
    • Supports deadlock free following methods. (PostgreSQL ONLY)
    • update, bulk_update, delete
  • PredefinedDefault (See Fields for more)
  • related_name must be provided when field's type is ForeignKey, OneToOneField or ManyToManyField.

You can use customized BaseUser and JWT based BaseToken by inherit it. See Authentication for more information about JWT authentication.

Fields

models.py

from django.db import models

from rest_base.fields import UniqueRandomPositiveInt32
from rest_base.models import BaseModel

class MyModel(BaseModel):
    unique_field = models.IntegerField(unique=True, default=UniqueRandomPositiveInt32)

If your model inherits rest_base.models.BaseModel, you can set the default value as

  • UniqueRandomPositiveInt32
  • UniqueRandomPositiveInt52
  • UniqueRandomPositiveInt64
  • UniqueRandomChar (unique random url-safe characters)

Then default value will be replaced with unique random value in the run-time.

Admin

admin.py

from django.contrib import admin

from rest_base.admin import model_admin
from .models import *

admin.site.register(*model_admin(MyModel))

You can easily register you models to Django admin page by using rest_base.admin.model_admin. It registers all of the model's fields and supports link to ForeignKey, OneToOneField and ManyToManyField on Django admin.

Authentication

pip install django-rest-base[jwt]

models.py

from rest_base.models import BaseToken

class Token(BaseToken):
    pass

settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_base.authentication.CsrfExemptSessionAuthentication',
        'rest_base.authentication.TokenAuthentication',
    ),
}

REST_BASE = {
    'AUTHENTICATION_MODEL': 'my_app.models.Token',
}

views.py

from rest_framework.decorators import permission_classes
from rest_framework.permissions import IsAuthenticated


@permission_classes((IsAuthenticated,))
def my_view(request):
    ...

Each Token which inherits BaseToken has public_key and secret_key. You can make bearer using following format.

// Header
{
  "alg": "HS256",
  "typ": "JWT",
  "public_key": "public_key",
  "nonce": 31
}
// Payload
{
  "query": {
    "key": "value"
  }
}

Then set the HTTP Authorization header to

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsInB1YmxpY19rZXkiOiJwdWJsaWNfa2V5Iiwibm9uY2UiOjMxfQ.eyJxdWVyeSI6eyJrZXkiOiJ2YWx1ZSJ9fQ.q1849tjsSspbtyBYHxsmS98FLUIG2W97aj_gaCxWGlg

Remember that nonce must be a positive int32 value which increases for each request.

Sentry

pip install django-rest-base[sentry]

settings.py

REST_BASE = {
    'SENTRY_HOST': 'https://<key>@sentry.io/<project>',
    'SENTRY_VERBOSE': False,  # report handled exceptions, default False
}

If sentry-sdk installed, SENTRY_HOST defined and rest_base.errors.exception_handler configured correctly, every unhandled exception from view will be reported to the Sentry.

Handled exceptions also reported if you set SENTRY_VERBOSE to True.

Channels

pip install django-rest-base[channels]

routing.py

from django.urls import path
from rest_base.channels.routing import NullURLRouter

websocket_urlpatterns = [
    path('app/', NullURLRouter(my_app.routing.websocket_urlpatterns)),
]

Etc

  • By default, startapp command will use template in rest_base/conf/app_template which contains additional code for Django REST base
  • .env can be loaded by
from rest_base.utils import dotenv

dotenv.load('path/to/.env')
  • You can dump/load predefined model instances by using
python manage.py dump my_app.Model
python manage.py load my_app.Model

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-rest-base-0.1.8.tar.gz (21.1 kB view hashes)

Uploaded Source

Built Distribution

django_rest_base-0.1.8-py3-none-any.whl (27.3 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page