Skip to main content

Django Ninja AIO CRUD - Rest Framework

Project description

🥷 django-ninja-aio-crud

[!NOTE] Django ninja aio crud framework is based on Django Ninja framework. It comes out with built-in views and models which are able to make automatic async CRUD operations and codes views class based making the developers' life easier and the code cleaner.

📝 Instructions

📚 Prerequisites

  • Install Python from the official website (latest version) and ensure it is added to the system Path and environment variables.

💻 Setup your environment

  • Create a virtual environment
python -m venv .venv

✅ Activate it

  • If you are from linux activate it with
. .venv/bin/activate
  • If you are from windows activate it with
. .venv/Scripts/activate

📥 Install package

pip install django-ninja-aio-crud

🚀 Usage

[!TIP] If you find django ninja aio crud useful, consider :star: this project and why not ... Buy me a coffee

ModelSerializer

  • You can serialize your models using ModelSerializer and made them inherit from it. In your models.py import ModelSerializer
# models.py
from django.db import models
from ninja_aio.models import ModelSerializer


class Foo(ModelSerializer):
  name = models.CharField(max_length=30)
  bar = models.CharField(max_length=30)

  class ReadSerializer:
    fields = ["id", "name", "bar"]

  class CreateSerializer:
    fields = ["name", "bar"]

  class UpdateSerializer:
    fields = ["name", "bar"]
  • ReadSerializer, CreateSerializer, UpdateSerializer are used to define which fields would be included in runtime schemas creation. You can also specify custom fields and handle their function by overriding custom_actions ModelSerializer's method(custom fields are only available for Create and Update serializers).
# models.py
from django.db import models
from ninja_aio.models import ModelSerializer


class Foo(ModelSerializer):
  name = models.CharField(max_length=30)
  bar = models.CharField(max_length=30)
  active = models.BooleanField(default=False)

  class ReadSerializer:
    fields = ["id", "name", "bar"]

  class CreateSerializer:
    customs = [("force_activation", bool, False)]
    fields = ["name", "bar"]

  class UpdateSerializer:
    fields = ["name", "bar"]

  async def custom_actions(self, payload: dict[str, Any]):
      if not payload.get("force_activation"):
          return
      setattr(self, "force_activation", True)
  
  async def post_create(self) -> None:
      if not hasattr(self, "force_activation") or not getattr(self, "force_activation"):
          return
      self.active = True
      await self.asave()
  • post create method is a custom method that comes out to handle actions which will be excuted after that the object is created. It can be used, indeed, for example to handle custom fields' actions.

APIViewSet

  • View class used to automatically generate CRUD views. in your views.py import APIViewSet and define your api using NinjaAIO class. NinjaAIO class uses built-in parser and renderer which use orjson for data serialization.
# views.py
from ninja_aio import NinjaAIO
from ninja_aio.views import APIViewSet
from ninja_aio.parsers import ORJSONParser
from ninja_aio.renders import ORJSONRender

from .models import Foo

api = NinjaAIO()


class FooAPI(APIViewSet):
  model = Foo
  api = api

  
FooAPI().add_views_to_route()
  • and that's it, your model CRUD will be automatically created. You can also add custom views to CRUD overriding the built-in method "views".
# views.py
from ninja import Schema
from ninja_aio import NinjaAIO
from ninja_aio.views import APIViewSet
from ninja_aio.parsers import ORJSONParser
from ninja_aio.renders import ORJSONRender

from .models import Foo

api = NinjaAIO()


class ExampleSchemaOut(Schema):
  sum: float


class ExampleSchemaIn(Schema):
  n1: float
  n2: float


class FooAPI(APIViewSet):
  model = Foo
  api = api

  def views(self):
    @self.router.post("numbers-sum/", response={200: ExampleSchemaOut})
    async def sum(request: HttpRequest, data: ExampleSchemaIn):
        return 200, {sum: data.n1 + data.n2}


FooAPI().add_views_to_route()

APIView

  • View class to code generic views class based. In your views.py import APIView class.
# views.py
from ninja import Schema
from ninja_aio import NinjaAIO
from ninja_aio.views import APIView
from ninja_aio.parsers import ORJSONParser
from ninja_aio.renders import ORJSONRender

api = NinjaAIO()


class ExampleSchemaOut(Schema):
  sum: float


class ExampleSchemaIn(Schema):
  n1: float
  n2: float


class SumView(APIView):
  api = api
  api_router_path = "numbers-sum/"
  router_tag = "Sum"

  def views(self):
    @self.router.post("/", response={200: ExampleSchemaOut})
    async def sum(request: HttpRequest, data: ExampleSchemaIn):
        return 200, {sum: data.n1 + data.n2}


SumView().add_views_to_route()

Relations

  • You can also set ForeignKey, OneToOne and ManyToMany relations into serialization(reverse relations are supported too). Django ninja aio crud will serialize every of these relation automatically.

  • Define models:

# models.py
class Bar(ModelSerializer):
    name = models.CharField(max_length=30)
    description = models.TextField(max_length=30)

    # ReadSerializer with reverse OneToMany relation (foos)
    class ReadSerializer:
        fields = ["id", "name", "description", "foos"]

    class CreateSerializer:
        fields = ["name", "description"]

    class UpdateSerializer:
        fields = ["name", "description"]


class Foo(ModelSerializer):
    name = models.CharField(max_length=30)
    bar = models.ForeignKey(Bar, on_delete=models.CASCADE, related_name="foos")

    class ReadSerializer:
        fields = ["id", "name", "bar"]

    class CreateSerializer:
        fields = ["name", "bar"]

    class UpdateSerializer:
        fields = ["name"]
  • Define views:
# views.py
from ninja_aio import NinjaAIO
from ninja_aio.views import APIViewSet
from ninja_aio.parsers import ORJSONParser
from ninja_aio.renders import ORJSONRender

from .models import Foo, Bar

api = NinjaAIO()


class FooAPI(APIViewSet):
  model = Foo
  api = api


class BarAPI(APIViewSet):
  model = Bar
  api = api


FooAPI().add_views_to_route()
BarAPI().add_views_to_route()
  • Now run your server and go to /docs url:

Docs

  • Foo Schemas

Swagger UI

  • Bar Schemas with reverse relation

Swagger UI

🔒 Authentication

Jwt

  • AsyncJWTBearer built-in class is an authenticator class which use joserfc module. It cames out with authenticate method which validate given claims. Override auth handler method to write your own authentication method. Default algorithms used is RS256. a jwt Token istance is set as class atribute so you can use it by self.dcd.
from ninja_aio.auth import AsyncJWTBearer
from django.conf import settings
from django.http import HttpRequest

from .models import Foo


class CustomJWTBearer(AsyncJWTBearer):
    jwt_public = settings.JWT_PUBLIC
    claims = {"foo_id": {"essential": True}}

    async def auth_handler(self, request: HttpRequest):
      try:
        request.user = await Foo.objects.aget(id=self.dcd.claims["foo_id"])
      except Foo.DoesNotExist:
        return None
      return request.user
  • Then add it to views.
# views.py
from ninja import Schema
from ninja_aio import NinjaAIO
from ninja_aio.views import APIViewSet, APIView
from ninja_aio.parsers import ORJSONParser
from ninja_aio.renders import ORJSONRender

from .models import Foo

api = NinjaAIO()


class FooAPI(APIViewSet):
  model = Foo
  api = api
  auths = CustomJWTBearer()


class ExampleSchemaOut(Schema):
  sum: float


class ExampleSchemaIn(Schema):
  n1: float
  n2: float


class SumView(APIView):
  api = api
  api_router_path = "numbers-sum/"
  router_tag = "Sum"
  auths = CustomJWTBearer()

  def views(self):
    @self.router.post("/", response={200: ExampleSchemaOut}, auth=self.auths)
    async def sum(request: HttpRequest, data: ExampleSchemaIn):
        return 200, {sum: data.n1 + data.n2}


FooAPI().add_views_to_route()
SumView().add_views_to_route()

📝 Pagination

  • By default APIViewSet list view uses Django Ninja built-in AsyncPagination class "PageNumberPagination". You can customize and assign it to APIViewSet class. To make your custom pagination consult Django Ninja pagination documentation.
# views.py

class FooAPI(APIViewSet):
  model = Foo
  api = api
  pagination_class = CustomPaginationClass

📌 Notes

  • Feel free to contribute and improve the program. 🛠️

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_ninja_aio_crud-0.2.1.tar.gz (10.9 kB view hashes)

Uploaded Source

Built Distribution

django_ninja_aio_crud-0.2.1-py3-none-any.whl (10.9 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