Skip to main content

Django Schema - Builds Pydantic Schemas from Django Models with default field type validations

Project description

Test PyPI version PyPI version PyPI version Codecov Downloads

Ninja Schema

Ninja Schema converts your Django ORM models to Pydantic schemas with more Pydantic features supported.

Inspired by: django-ninja and djantic

Notice

Starting version 0.13.4, Ninja schema will support both v1 and v2 of pydantic library and will closely monitor V1 support on pydantic package.

Requirements

Python >= 3.8 django >= 3 pydantic >= 1.6

Key features:

  • Custom Field Support: Ninja Schema converts django model to native pydantic types which gives you quick field validation out of the box. eg Enums, email, IPAddress, URLs, JSON, etc
  • Field Validator: Fields can be validated with model_validator just like pydantic validator or root_validator.

Installation

pip install ninja-schema

Example

Checkout this sample project: https://github.com/eadwinCode/bookstoreapi

Configuration Properties

  • model: Django Model
  • include: Fields to include, default: '__all__'. Please note that when include = __all__, model's PK becomes optional
  • exclude: Fields to exclude, default: set()
  • optional: Fields to mark optional, default: set() optional = '__all__' will make all schema fields optional
  • depth: defines depth to nested generated schema, default: 0

model_validator(*args, **kwargs)

model_validator is a substitute for pydantic validator used for pre and post fields validation. There functionalities are the same. More info pydantic validators

from django.contrib.auth import get_user_model
from ninja_schema import ModelSchema, model_validator

UserModel = get_user_model()


class CreateUserSchema(ModelSchema):
    class Config:
        model = UserModel
        include = ['username', 'email', 'password']

    @model_validator('username')
    def validate_unique_username(cls, value_data: str) -> str:
        if UserModel.objects.filter(username__icontains=value_data).exists():
            raise ValueError('Username exists')
        return value_data

from_orm(cls, obj: Any)

You can generate a schema instance from your django model instance

from django.contrib.auth import get_user_model
from ninja_schema import ModelSchema, model_validator

UserModel = get_user_model()
new_user = UserModel.objects.create_user(
    username='eadwin', email='eadwin@example.com', 
    password='password', first_name='Emeka', last_name='Okoro'
)


class UserSchema(ModelSchema):
    class Config:
        model = UserModel
        include = ['id','first_name', 'last_name', 'username', 'email']

schema = UserSchema.from_orm(new_user)
print(schema.json(indent=2)
{
    "id": 1,
    "first_name": "Emeka",
    "last_name": "Okoro",
    "email": "eadwin@example.com",
    "username": "eadwin",
}

apply_to_model(self, model_instance, **kwargs)

You can transfer data from your ModelSchema to Django Model instance using the apply function. The apply_to_model function uses Pydantic model .dict function, dict function filtering that can be passed as kwargs to the .apply function.

For more info, visit Pydantic model export

from django.contrib.auth import get_user_model
from ninja_schema import ModelSchema

UserModel = get_user_model()
new_user = UserModel.objects.create_user(username='eadwin', email='eadwin@example.com', password='password')


class UpdateUserSchema(ModelSchema):
    class Config:
        model = UserModel
        include = ['first_name', 'last_name', 'username']
        optional = ['username']  # `username` is now optional

schema = UpdateUserSchema(first_name='Emeka', last_name='Okoro')
schema.apply_to_model(new_user, exclude_none=True)

assert new_user.first_name == 'Emeka' # True
assert new_user.username == 'eadwin' # True

Generated Schema Sample

from django.contrib.auth import get_user_model
from ninja_schema import ModelSchema, model_validator

UserModel = get_user_model()


class UserSchema(ModelSchema):
    class Config:
        model = UserModel
        include = '__all__'
        depth = 2

        
print(UserSchema.schema())

{
    "title": "UserSchema",
    "type": "object",
    "properties": {
        "id": {"title": "Id", "extra": {}, "type": "integer"},
        "password": {"title": "Password", "maxLength": 128, "type": "string"},
        "last_login": {"title": "Last Login","type": "string", "format": "date-time"},
        "is_superuser": {"title": "Superuser Status",
            "description": "Designates that this user has all permissions without explicitly assigning them.",
            "default": false,
            "type": "boolean"
        },
        "username": {
            "title": "Username",
            "description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
            "maxLength": 150,
            "type": "string"
        },
        "first_name": {
            "title": "First Name",
            "maxLength": 150,
            "type": "string"
        },
        "last_name": {
            "title": "Last Name",
            "maxLength": 150,
            "type": "string"
        },
        "email": {
            "title": "Email Address",
            "type": "string",
            "format": "email"
        },
        "is_staff": {
            "title": "Staff Status",
            "description": "Designates whether the user can log into this admin site.",
            "default": false,
            "type": "boolean"
        },
        "is_active": {
            "title": "Active",
            "description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
            "default": true,
            "type": "boolean"
        },
        "date_joined": {
            "title": "Date Joined",
            "type": "string",
            "format": "date-time"
        },
        "groups": {
            "title": "Groups",
            "description": "The groups this user belongs to. A user will get all permissions granted to each of their groups.",
            "type": "array",
            "items": {
                "$ref": "#/definitions/Group"
            }
        },
        "user_permissions": {
            "title": "User Permissions",
            "description": "Specific permissions for this user.",
            "type": "array",
            "items": {
                "$ref": "#/definitions/Permission"
            }
        }
    },
    "required": [
        "password",
        "username",
        "groups",
        "user_permissions"
    ],
    "definitions": {
        "Permission": {
            "title": "Permission",
            "type": "object",
            "properties": {
                "id": {
                    "title": "Id",
                    "extra": {},
                    "type": "integer"
                },
                "name": {
                    "title": "Name",
                    "maxLength": 255,
                    "type": "string"
                },
                "content_type_id": {
                    "title": "Content Type",
                    "type": "integer"
                },
                "codename": {
                    "title": "Codename",
                    "maxLength": 100,
                    "type": "string"
                }
            },
            "required": [
                "name",
                "content_type_id",
                "codename"
            ]
        },
        "Group": {
            "title": "Group",
            "type": "object",
            "properties": {
                "id": {
                    "title": "Id",
                    "extra": {},
                    "type": "integer"
                },
                "name": {
                    "title": "Name",
                    "maxLength": 150,
                    "type": "string"
                },
                "permissions": {
                    "title": "Permissions",
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/Permission"
                    }
                }
            },
            "required": [
                "name",
                "permissions"
            ]
        }
    }
}

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ninja_schema-0.14.3.tar.gz (18.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ninja_schema-0.14.3-py3-none-any.whl (20.8 kB view details)

Uploaded Python 3

File details

Details for the file ninja_schema-0.14.3.tar.gz.

File metadata

  • Download URL: ninja_schema-0.14.3.tar.gz
  • Upload date:
  • Size: 18.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for ninja_schema-0.14.3.tar.gz
Algorithm Hash digest
SHA256 7edce24c3fd8c15ab2dc38423af9417a58b4dd9e156d67be77815ebed46af952
MD5 8f446c0b2c82aea4086c60cca837f9a7
BLAKE2b-256 2215b8bdcd7f685f51ccbc2f6306aaccb12c07708fa4d00c463e980520f448bd

See more details on using hashes here.

File details

Details for the file ninja_schema-0.14.3-py3-none-any.whl.

File metadata

  • Download URL: ninja_schema-0.14.3-py3-none-any.whl
  • Upload date:
  • Size: 20.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for ninja_schema-0.14.3-py3-none-any.whl
Algorithm Hash digest
SHA256 b6e8ca08e793b7f91922f488c3b47cd62252e5fb076093c1cf527eae1e891751
MD5 5cca721ac4517adcbad1f943c5cd1aeb
BLAKE2b-256 3855b0b35229b01f28163f964c5185f9d602dd588040134cec1bb2c29b95c15d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page