django-ninja-aio-crud


Namedjango-ninja-aio-crud JSON
Version 0.2.2 PyPI version JSON
download
home_pageNone
SummaryDjango Ninja AIO CRUD - Rest Framework
upload_time2024-10-03 00:30:06
maintainerNone
docs_urlNone
authorGiuseppe Casillo
requires_python>=3.10
licenseNone
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 🥷 django-ninja-aio-crud
> [!NOTE]
> Django ninja aio crud framework is based on **<a href="https://django-ninja.dev/">Django Ninja framework</a>**. 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](https://www.python.org/) (latest version) and ensure it is added to the system Path and environment variables.

### 💻 Setup your environment

- Create a virtual environment
```bash
python -m venv .venv
```

### ✅ Activate it

- If you are from linux activate it with

```bash
. .venv/bin/activate
```

- If you are from windows activate it with

```bash
. .venv/Scripts/activate
```

### 📥 Install package

```bash
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](https://buymeacoffee.com/caspel26)

### ModelSerializer

- You can serialize your models using ModelSerializer and made them inherit from it. In your models.py import ModelSerializer
```Python
# 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).

```Python
# 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.

```Python
# 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".

```Python
# 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.

```Python
# 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:

```Python
# 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:

```Python
# 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](docs/images/foo-swagger.png)

- Bar Schemas with reverse relation

![Swagger UI](docs/images/bar-swagger.png)

## 🔒 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.  

```Python
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.

```Python
# 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 **<a href="https://django-ninja.dev/guides/response/pagination/#async-pagination">Django Ninja pagination documentation</a>**.

```Python
# views.py

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

```

## 📌 Notes
- Feel free to contribute and improve the program. 🛠️


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "django-ninja-aio-crud",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": "Giuseppe Casillo",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/7e/78/218f0f5dc49fe3755d13e0c8094f1bc51c781563580f381cd375c6b03599/django_ninja_aio_crud-0.2.2.tar.gz",
    "platform": null,
    "description": "# \ud83e\udd77 django-ninja-aio-crud\n> [!NOTE]\n> Django ninja aio crud framework is based on **<a href=\"https://django-ninja.dev/\">Django Ninja framework</a>**. 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.\n\n## \ud83d\udcdd Instructions\n\n### \ud83d\udcda Prerequisites\n\n- Install Python from the [official website](https://www.python.org/) (latest version) and ensure it is added to the system Path and environment variables.\n\n### \ud83d\udcbb Setup your environment\n\n- Create a virtual environment\n```bash\npython -m venv .venv\n```\n\n### \u2705 Activate it\n\n- If you are from linux activate it with\n\n```bash\n. .venv/bin/activate\n```\n\n- If you are from windows activate it with\n\n```bash\n. .venv/Scripts/activate\n```\n\n### \ud83d\udce5 Install package\n\n```bash\npip install django-ninja-aio-crud\n```\n\n## \ud83d\ude80 Usage\n\n> [!TIP]\n> If you find **django ninja aio crud** useful, consider :star: this project\n> and why not ... [Buy me a coffee](https://buymeacoffee.com/caspel26)\n\n### ModelSerializer\n\n- You can serialize your models using ModelSerializer and made them inherit from it. In your models.py import ModelSerializer\n```Python\n# models.py\nfrom django.db import models\nfrom ninja_aio.models import ModelSerializer\n\n\nclass Foo(ModelSerializer):\n  name = models.CharField(max_length=30)\n  bar = models.CharField(max_length=30)\n\n  class ReadSerializer:\n    fields = [\"id\", \"name\", \"bar\"]\n\n  class CreateSerializer:\n    fields = [\"name\", \"bar\"]\n\n  class UpdateSerializer:\n    fields = [\"name\", \"bar\"]\n```\n\n- 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).\n\n```Python\n# models.py\nfrom django.db import models\nfrom ninja_aio.models import ModelSerializer\n\n\nclass Foo(ModelSerializer):\n  name = models.CharField(max_length=30)\n  bar = models.CharField(max_length=30)\n  active = models.BooleanField(default=False)\n\n  class ReadSerializer:\n    fields = [\"id\", \"name\", \"bar\"]\n\n  class CreateSerializer:\n    customs = [(\"force_activation\", bool, False)]\n    fields = [\"name\", \"bar\"]\n\n  class UpdateSerializer:\n    fields = [\"name\", \"bar\"]\n\n  async def custom_actions(self, payload: dict[str, Any]):\n      if not payload.get(\"force_activation\"):\n          return\n      setattr(self, \"force_activation\", True)\n  \n  async def post_create(self) -> None:\n      if not hasattr(self, \"force_activation\") or not getattr(self, \"force_activation\"):\n          return\n      self.active = True\n      await self.asave()\n```\n\n- 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.\n\n\n### APIViewSet\n\n- 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.\n\n```Python\n# views.py\nfrom ninja_aio import NinjaAIO\nfrom ninja_aio.views import APIViewSet\nfrom ninja_aio.parsers import ORJSONParser\nfrom ninja_aio.renders import ORJSONRender\n\nfrom .models import Foo\n\napi = NinjaAIO()\n\n\nclass FooAPI(APIViewSet):\n  model = Foo\n  api = api\n\n  \nFooAPI().add_views_to_route()\n```\n\n- 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\".\n\n```Python\n# views.py\nfrom ninja import Schema\nfrom ninja_aio import NinjaAIO\nfrom ninja_aio.views import APIViewSet\nfrom ninja_aio.parsers import ORJSONParser\nfrom ninja_aio.renders import ORJSONRender\n\nfrom .models import Foo\n\napi = NinjaAIO()\n\n\nclass ExampleSchemaOut(Schema):\n  sum: float\n\n\nclass ExampleSchemaIn(Schema):\n  n1: float\n  n2: float\n\n\nclass FooAPI(APIViewSet):\n  model = Foo\n  api = api\n\n  def views(self):\n    @self.router.post(\"numbers-sum/\", response={200: ExampleSchemaOut})\n    async def sum(request: HttpRequest, data: ExampleSchemaIn):\n        return 200, {sum: data.n1 + data.n2}\n\n\nFooAPI().add_views_to_route()\n```\n\n### APIView\n\n- View class to code generic views class based. In your views.py import APIView class.\n\n```Python\n# views.py\nfrom ninja import Schema\nfrom ninja_aio import NinjaAIO\nfrom ninja_aio.views import APIView\nfrom ninja_aio.parsers import ORJSONParser\nfrom ninja_aio.renders import ORJSONRender\n\napi = NinjaAIO()\n\n\nclass ExampleSchemaOut(Schema):\n  sum: float\n\n\nclass ExampleSchemaIn(Schema):\n  n1: float\n  n2: float\n\n\nclass SumView(APIView):\n  api = api\n  api_router_path = \"numbers-sum/\"\n  router_tag = \"Sum\"\n\n  def views(self):\n    @self.router.post(\"/\", response={200: ExampleSchemaOut})\n    async def sum(request: HttpRequest, data: ExampleSchemaIn):\n        return 200, {sum: data.n1 + data.n2}\n\n\nSumView().add_views_to_route()\n```\n\n### Relations\n- 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.\n\n- Define models:\n\n```Python\n# models.py\nclass Bar(ModelSerializer):\n    name = models.CharField(max_length=30)\n    description = models.TextField(max_length=30)\n\n    # ReadSerializer with reverse OneToMany relation (foos)\n    class ReadSerializer:\n        fields = [\"id\", \"name\", \"description\", \"foos\"]\n\n    class CreateSerializer:\n        fields = [\"name\", \"description\"]\n\n    class UpdateSerializer:\n        fields = [\"name\", \"description\"]\n\n\nclass Foo(ModelSerializer):\n    name = models.CharField(max_length=30)\n    bar = models.ForeignKey(Bar, on_delete=models.CASCADE, related_name=\"foos\")\n\n    class ReadSerializer:\n        fields = [\"id\", \"name\", \"bar\"]\n\n    class CreateSerializer:\n        fields = [\"name\", \"bar\"]\n\n    class UpdateSerializer:\n        fields = [\"name\"]\n```\n\n- Define views:\n\n```Python\n# views.py\nfrom ninja_aio import NinjaAIO\nfrom ninja_aio.views import APIViewSet\nfrom ninja_aio.parsers import ORJSONParser\nfrom ninja_aio.renders import ORJSONRender\n\nfrom .models import Foo, Bar\n\napi = NinjaAIO()\n\n\nclass FooAPI(APIViewSet):\n  model = Foo\n  api = api\n\n\nclass BarAPI(APIViewSet):\n  model = Bar\n  api = api\n\n\nFooAPI().add_views_to_route()\nBarAPI().add_views_to_route()\n```\n\n- Now run your server and go to /docs url:\n\n### Docs\n\n- Foo Schemas\n\n![Swagger UI](docs/images/foo-swagger.png)\n\n- Bar Schemas with reverse relation\n\n![Swagger UI](docs/images/bar-swagger.png)\n\n## \ud83d\udd12 Authentication\n\n### Jwt\n\n- 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.  \n\n```Python\nfrom ninja_aio.auth import AsyncJWTBearer\nfrom django.conf import settings\nfrom django.http import HttpRequest\n\nfrom .models import Foo\n\n\nclass CustomJWTBearer(AsyncJWTBearer):\n    jwt_public = settings.JWT_PUBLIC\n    claims = {\"foo_id\": {\"essential\": True}}\n\n    async def auth_handler(self, request: HttpRequest):\n      try:\n        request.user = await Foo.objects.aget(id=self.dcd.claims[\"foo_id\"])\n      except Foo.DoesNotExist:\n        return None\n      return request.user\n```\n\n- Then add it to views.\n\n```Python\n# views.py\nfrom ninja import Schema\nfrom ninja_aio import NinjaAIO\nfrom ninja_aio.views import APIViewSet, APIView\nfrom ninja_aio.parsers import ORJSONParser\nfrom ninja_aio.renders import ORJSONRender\n\nfrom .models import Foo\n\napi = NinjaAIO()\n\n\nclass FooAPI(APIViewSet):\n  model = Foo\n  api = api\n  auths = CustomJWTBearer()\n\n\nclass ExampleSchemaOut(Schema):\n  sum: float\n\n\nclass ExampleSchemaIn(Schema):\n  n1: float\n  n2: float\n\n\nclass SumView(APIView):\n  api = api\n  api_router_path = \"numbers-sum/\"\n  router_tag = \"Sum\"\n  auths = CustomJWTBearer()\n\n  def views(self):\n    @self.router.post(\"/\", response={200: ExampleSchemaOut}, auth=self.auths)\n    async def sum(request: HttpRequest, data: ExampleSchemaIn):\n        return 200, {sum: data.n1 + data.n2}\n\n\nFooAPI().add_views_to_route()\nSumView().add_views_to_route()\n```\n\n## \ud83d\udcdd Pagination\n\n- 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 **<a href=\"https://django-ninja.dev/guides/response/pagination/#async-pagination\">Django Ninja pagination documentation</a>**.\n\n```Python\n# views.py\n\nclass FooAPI(APIViewSet):\n  model = Foo\n  api = api\n  pagination_class = CustomPaginationClass\n\n```\n\n## \ud83d\udccc Notes\n- Feel free to contribute and improve the program. \ud83d\udee0\ufe0f\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Django Ninja AIO CRUD - Rest Framework",
    "version": "0.2.2",
    "project_urls": {
        "Repository": "https://github.com/caspel26/django-ninja-aio-crud"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e323458a83bc888d8764b54f8e34eb57be87e4b904c734da829f9c9ea899b21c",
                "md5": "1d5f74bc9c3ee1b4c1f1beeff0d393e7",
                "sha256": "86e07f0a92bcbb88659e25fe62e70ffc368257b880ec3ff264a5a206e1ef80bf"
            },
            "downloads": -1,
            "filename": "django_ninja_aio_crud-0.2.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1d5f74bc9c3ee1b4c1f1beeff0d393e7",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 10892,
            "upload_time": "2024-10-03T00:30:04",
            "upload_time_iso_8601": "2024-10-03T00:30:04.719016Z",
            "url": "https://files.pythonhosted.org/packages/e3/23/458a83bc888d8764b54f8e34eb57be87e4b904c734da829f9c9ea899b21c/django_ninja_aio_crud-0.2.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7e78218f0f5dc49fe3755d13e0c8094f1bc51c781563580f381cd375c6b03599",
                "md5": "45b205f286fbb28ec0fd45370f56f9f6",
                "sha256": "96e699f358e099cca2f9ad480303570da4460ff590b964edd8afef5921cdd0be"
            },
            "downloads": -1,
            "filename": "django_ninja_aio_crud-0.2.2.tar.gz",
            "has_sig": false,
            "md5_digest": "45b205f286fbb28ec0fd45370f56f9f6",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 10827,
            "upload_time": "2024-10-03T00:30:06",
            "upload_time_iso_8601": "2024-10-03T00:30:06.565077Z",
            "url": "https://files.pythonhosted.org/packages/7e/78/218f0f5dc49fe3755d13e0c8094f1bc51c781563580f381cd375c6b03599/django_ninja_aio_crud-0.2.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-03 00:30:06",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "caspel26",
    "github_project": "django-ninja-aio-crud",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "django-ninja-aio-crud"
}
        
Elapsed time: 0.37962s