Skip to content

Form Data

Django Ninja also allows you to parse and validate request.POST data (that is, application/x-www-form-urlencoded or multipart/form-data).

Form Data as Parameters

from ninja import NinjaAPI, Form

@api.post("/login")
def login(request, username: Form[str], password: Form[str]):
    return {'username': username, 'password': '*****'}

Note the following:

1) You need to import the Form class from ninja

from ninja import Form

2) Use Form as the default value for the parameter:

username: Form[str]

Using a Schema

Similar to Request Body, you can use a schema to organize your parameters.

from ninja import Form, Schema


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


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

Request Form + Path + Query Parameters

Similar to Request Body, you can combine form data with other parameter sources.

You can declare query parameters and path parameters and form fields, etc. 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 Form(...) should be taken from the request form fields, and so on.

from ninja import Form, Schema


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


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

Mapping Empty Form Fields to Default Values

Optional form fields are often sent with empty values. This value is interpreted as an empty string, so for fields such as int or bool, it may fail validation.

As described in the Pydantic documentation, this can be solved by using generic classes as types.

from ninja import Form, Schema
from typing import Annotated, TypeVar
from pydantic import WrapValidator
from pydantic_core import PydanticUseDefault


def _empty_str_to_default(v, handler, info):
    if isinstance(v, str) and v == '':
        raise PydanticUseDefault
    return handler(v)


T = TypeVar('T')
EmptyStrToDefault = Annotated[T, WrapValidator(_empty_str_to_default)]


class Item(Schema):
    name: str
    description: str = None
    price: EmptyStrToDefault[float] = 0.0
    quantity: EmptyStrToDefault[int] = 0
    in_stock: EmptyStrToDefault[bool] = True


@api.post("/items-blank-default")
def update(request, item: Form[Item]):
    return item.dict()

Done

Continue to the next chapter! File Uploads

Comments


本文总阅读量次