.. _ninja: .. index:: single: Django Ninja Django Ninja - ein asynchrones Restframework für Django ********************************************************* https://www.youtube.com/watch?v=S4nUhruExwA aktuell 8:00 Installation ============ In die ``requirements.in`` wird eingetragen: .. code-block:: bash django-ninja .. code-block:: bash pip-compile requirements.in pip-sync requirements-dev.txt requirements.txt Vorarbeiten ============ Eine neue App namens ``tickets`` erstellen und ein Model anlegen. .. code-block:: bash python manage.py startapp tickets In die neu erstellt App legen wir unter ``models.py`` ein Model für ein Ticket an. .. code-block:: python from django.db import models from event_manager.mixins import DateMixin class Ticket(DateMixin): class Status(models.TextChoices): "new", "new" status = models.CharField(max_length=20, choices=Status.choices) und führen wir gewohnt ``makemirations`` und ``migrate`` aus. Unter ``event_manager/tickets`` legen wir nun eine Datei ``api.py``, in der der Quellcode für die Ninja-API liegen wird. Wir legen auch noch eine urls.py an. Unser neues tickets-verzeichnis sieht nun so aus: .. code-block:: bash . ├── admin.py ├── api.py ├── apps.py ├── __init__.py ├── migrations ├── models.py ├── tests.py ├── urls.py └── views.py Legen wir zuerst unter ``event_manager/event_manager/urls.py`` die Verknüpfung zu unserer Api fest, damit die API-Endpunkte auch gefunden werden können. .. code-block:: python urlpatterns = [ ... path("api/tickets/", include("tickets.urls")), ... ] in die ``event_manager/tickets/urls.py`` tragen wir folgendes ein: .. code-block:: python from django.urls import path from .api import api urlpatters = [ path("", api.urls), ] Die tatsächlichen Routen erzeugt Django-Ninja automatisch für uns. Der erste Endpunkt ========================== Unter ``event_manager/tickets/api.py`` tragen wir folgenden Code ein: .. code-block:: python from ninja import NinjaAPI api = NinjaAPI() @api.get("/") def home(request): return "Hello World" Hier haben wir einen Endpunkt erstellt, der jetzt unter ``http://127.0.0.1:8000/api/tickets/`` erreichbar ist. Die URL hat Django-Ninja für uns selbst erstellt, auch um die Serialisierung mussten wir uns nicht kümmern. Ticket erstellen ========================== Um ein Ticket zu erstellen, benötigen wir das Django ORM. Um die Eingangsdaten allerdings erstmal zu validieren, legen wir ein ``Schema`` an .. code-block:: python from ninja import ModelSchema, Schema from .models import Ticket class MessageIn(Schema): title: str msg: str Und definieren in ``api.py`` den entsprechenden Endpunkt. .. code-block:: python from .schema import MessageIn @api.post("msg") def msg(request, data: MessageIn): return data jetzt können wir das zum Beispiel mit curl testen .. code-block:: bash curl http://127.0.0.1:8000/api/tickets/msg -d '{"title":"wow", "msg":"hi there!"}' -X POST Das hat geklappt! Jetzt legen wir ein eingehendes Schema für ein Ticket an: .. code-block:: python class TicketIn(ModelSchema): class Config: model = Ticket model_fields = ("status",) Und definieren in ``api.py`` einen weiteren Endpunkt. .. code-block:: python @api.post("/") def ticket_add(request, data: TicketIn) -> dict: ticket = Ticket.objects.create(**data.dict()) return {"result": "success", "id": ticket.id} Um ein neues Ticket anzulegen, brauchen wir wieder curl: .. code-block:: bash curl http://127.0.0.1:8000/api/tickets/ -d '{"status":"new"}' -X POST Falls die Eingabedaten falsch sind, bekommen wir einen Fehler serviert .. code-block:: bash curl http://127.0.0.1:8000/api/tickets/ -d '{"status":"neu"}' -X POST -vv curl http://127.0.0.1:8000/api/tickets/3 -d '{"status":"neu"}' -X PUT Um ein Ticket upzudaten, können wir die HTTP-Methoden put oder patch nutzen. Für put machen wir es so .. code-block:: python @api.put("/put/{ticket_id}") def ticket_put(request, ticket_id: int, payload: TicketIn): obj = get_object_or_404(Ticket, pk=ticket_id) for attr, value in payload.dict().items(): if value: setattr(obj, attr, value) return {"id": obj.pk} curl -X PUT http://127.0.0.1:8000/api/tickets/put/3 -d '{"status":"new"}' .. code-block:: python @api.delete("/{ticket_id}") def ticket_delete(request, ticket_id: int): obj = get_object_or_404(Ticket, pk=ticket_id) obj.delete() return {"success": True} curl -X DELETE http://127.0.0.1:8000/api/tickets/3