Skip to content

Request Body

The request body is typically used with "create" and "update" operations (POST, PUT, PATCH). For example, when creating a resource with POST or PUT, the request body usually contains a representation of the resource to be created.

To declare a request body, you need to use Django Ninja's Schema.

Note

Under the hood, Django Ninja leverages all the power and features of the Pydantic Model. The alias Schema was chosen to avoid code confusion when working with Django models, since Pydantic's model class is named Model by default, which conflicts with Django's Model class.

Importing Schema

First, you need to import Schema from ninja:

from typing import Optional
from ninja import Schema


class Item(Schema):
    name: str
    description: Optional[str] = None
    price: float
    quantity: int


@api.post("/items")
def create(request, item: Item):
    return item

Creating Your Data Model

Then declare your data model as a class that inherits from Schema.

Use standard Python types for all attributes:

from typing import Optional
from ninja import Schema


class Item(Schema):
    name: str
    description: Optional[str] = None
    price: float
    quantity: int


@api.post("/items")
def create(request, item: Item):
    return item

Note: if you set the default value of an attribute to None, it becomes optional in the request body. For example, the model above declares a JSON "object" (or Python dict) like this:

{
    "name": "Katana",
    "description": "An optional description",
    "price": 299.00,
    "quantity": 10
}

...since description is optional (its default value is None), this JSON "object" will also be valid:

{
    "name": "Katana",
    "price": 299.00,
    "quantity": 10
}

Declaring It as a Parameter

To add it to your path operation, declare it the same way you declare path and query parameters:

from typing import Optional
from ninja import Schema


class Item(Schema):
    name: str
    description: Optional[str] = None
    price: float
    quantity: int


@api.post("/items")
def create(request, item: Item):
    return item

... and declare its type as the Item model you created.

Result

With just that Python type declaration, Django Ninja will:

  • Read the request body as JSON.
  • Convert to the appropriate types (if needed).
  • Validate the data.
    • If the data is invalid, it will return a friendly and meaningful error that precisely indicates the location and content of the erroneous data.
  • Provide you with the received data in the parameter item.
    • Since you declared its type as Item in the function, you will also get editor support (autocomplete, etc.) for all attributes and their types.
  • Generate JSON Schema definitions for your model, which you can also use anywhere you need them in your project.
  • These schemas will become part of the generated OpenAPI schema and will be used by the automatic documentation UI.

Automatic Documentation

The JSON Schemas of your models will become part of your generated OpenAPI schema and will be displayed in the interactive API documentation:

Openapi schema

...and they will also be used in the API documentation for every path operation that requires them:

Openapi schema

Editor Support

In your editor, inside your function, you will get ubiquitous type hints and completion (this will not happen if you use a dict instead of a Schema object):

Type hints

The previous screenshots use Visual Studio Code.

You will get the same editor support in PyCharm and most other Python editors.

Request Body + Path Parameters

You can declare path parameters and request body at the same time.

Django Ninja will recognize that function parameters matching path parameters should be taken from the path, while function parameters declared with Schema should be taken from the request body.

from ninja import Schema


class Item(Schema):
    name: str
    description: str = None
    price: float
    quantity: int


@api.put("/items/{item_id}")
def update(request, item_id: int, item: Item):
    return {"item_id": item_id, "item": item.dict()}

Request Body + Path + Query Parameters

You can also declare request body, path, and query parameters at the same time.

Django Ninja will recognize each parameter and take the data from the correct location.

from ninja import Schema


class Item(Schema):
    name: str
    description: str = None
    price: float
    quantity: int


@api.post("/items/{item_id}")
def update(request, item_id: int, item: Item, q: str):
    return {"item_id": item_id, "item": item.dict(), "q": q}

Function parameters will be recognized as follows:

  • If the parameter is also declared in the path, it will be used as a path parameter.

  • If the parameter is a single type (such as int, float, str, bool, etc.), it will be interpreted as a query parameter.

  • If the parameter is declared as a Schema (or Pydantic BaseModel) type, it will be interpreted as a request body.

Done

Continue to the next chapter! Form Data

Comments


本文总阅读量次