drf-pydantic


Namedrf-pydantic JSON
Version 2.2.0 PyPI version JSON
download
home_pagehttps://github.com/georgebv/drf-pydantic
SummaryUse pydantic with the Django REST framework
upload_time2024-02-14 05:01:00
maintainer
docs_urlNone
authorGeorge Bocharov
requires_python>=3.9,<4.0
licenseMIT
keywords django drf pydantic typing rest api
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p align="center">
  <a href="https://github.com/georgebv/drf-pydantic/actions/workflows/test.yml" target="_blank">
    <img src="https://github.com/georgebv/drf-pydantic/actions/workflows/test.yml/badge.svg?event=pull_request" alt="Test Status">
  </a>
  <a href="https://codecov.io/gh/georgebv/drf-pydantic" target="_blank">
    <img src="https://codecov.io/gh/georgebv/drf-pydantic/branch/main/graph/badge.svg?token=GN9rxzIFMc" alt="Test Coverage"/>
  </a>
  <a href="https://badge.fury.io/py/drf-pydantic" target="_blank">
    <img src="https://badge.fury.io/py/drf-pydantic.svg" alt="PyPI version" height="20">
  </a>
</p>

<p align="center">
  <i>
    Use pydantic with Django REST framework
  </i>
</p>

- [Introduction](#introduction)
  - [Performance](#performance)
- [Installation](#installation)
- [Usage](#usage)
  - [General](#general)
  - [Existing Models](#existing-models)
  - [Nested Models](#nested-models)
  - [Manual Serializer Configuration](#manual-serializer-configuration)
    - [Per-Field Configuration](#per-field-configuration)
    - [Custom Serializer](#custom-serializer)

# Introduction

[Pydantic](https://pydantic-docs.helpmanual.io) is a Python library used to perform
data serialization and validation.

[Django REST framework](https://www.django-rest-framework.org) is a framework built
on top of [Django](https://www.djangoproject.com/) used to write REST APIs.

If you develop DRF APIs and rely on pydantic for data validation/(de)serialization ,
then `drf-pydantic` is for you 😍.

> ℹ️ **INFO**<br> > `drf_pydantic` supports `pydantic` v2. Due to breaking API changes in `pydantic`
> v2 support for `pydantic` v1 is available only in `drf_pydantic` 1.\*.\*.

## Performance

Translation between `pydantic` models and `DRF` serializers is done during class
creation (e.g., when you first import the model). This means that there will be
zero impact on the performance of your application
(server instance or serverless session)
when using `drf_pydantic` while your application is running.

# Installation

```shell
pip install drf-pydantic
```

# Usage

## General

Use `drf_pydantic.BaseModel` instead of `pydantic.BaseModel` when creating your
models:

```python
from drf_pydantic import BaseModel

class MyModel(BaseModel):
    name: str
    addresses: list[str]
```

`MyModel.drf_serializer` would be equvalent to the following DRF Serializer class:

```python
class MyModelSerializer:
    name = CharField(allow_null=False, required=True)
    addresses = ListField(
        allow_empty=True,
        allow_null=False,
        child=CharField(allow_null=False),
        required=True,
    )
```

Whenever you need a DRF serializer you can get it from the model like this:

```python
my_value = MyModel.drf_serializer(data={"name": "Van", addresses: ["Gym"]})
my_value.is_valid(raise_exception=True)
```

> ℹ️ **INFO**<br>
> Models created using `drf_pydantic` are fully idenditcal to those created by
> `pydantic`. The only change is the addition of the `drf_serializer` attribute.

## Existing Models

If you have an existing code base and you would like to add the `drf_serializer`
attribute only to some of your models, then I have great news 🥳 - you can easily
extend your existing `pydantic` models by adding `drf_pydantic.BaseModel` to the list
of parent classes of the model you want to extend.

Your existing pydantic models:

```python
from pydantic import BaseModel

class Pet(BaseModel):
    name: str

class Dog(Pet):
    breed: str
```

Update your `Dog` model and get serializer via the `drf_serializer`:

```python
from drf_pydantic import BaseModel as DRFBaseModel
from pydantic import BaseModel

class Pet(BaseModel):
    name: str

class Dog(DRFBaseModel, Pet):
    breed: str

Dog.drf_serializer
```

> ⚠️ **ATTENTION**<br>
> Inheritance order is important: `drf_pydantic.BaseModel` must always go before
> the `pydantic.BaseModel` class.

## Nested Models

If you have nested models and you want to generate serializer only from one of them,
you don't have to update all models - only update the model you need, `drf_pydantic`
will generate serializers for all normal nested `pydantic` models for free 🥷.

```python
from drf_pydantic import BaseModel as DRFBaseModel
from pydantic import BaseModel

class Apartment(BaseModel):
    floor: int
    tenant: str

class Building(BaseModel):
    address: str
    aparments: list[Apartment]

class Block(DRFBaseModel):
    buildings: list[Buildind]

Block.drf_serializer
```

## Manual Serializer Configuration

If `drf_pydantic` does not generate the serializer you need, you can either granularly
configure which DRF serializer fields to use for each pydantic field, or you can
create a custom serializer for the model altogether.

> ⚠️ **WARNING**<br>
> When manually configuring the serializer you are responsible for setting all
> properties of the fields (e.g., `allow_null`, `required`, `default`, etc.).
> `drf_pydantic` does not perform any introspection for fields that are manually
> configured or for any fields if a custom serializer is used.

### Per-Field Configuration

```python
from typing import Annotated

from drf_pydantic import BaseModel
from rest_framework.serializers import IntegerField

class Person(BaseModel):
    name: str
    age: Annotated[float, IntegerField(min_value=0, max_value=100)]
```

### Custom Serializer

In example below, `Person` will use `MyCustomSerializer` as its drf serializer.
`Employee` will have its own serializer generated by `drf_pydantic` because it
does not have a user-defined `drf_serializer` attribute (it's never inherited).
`Company` will have its own serializer generated by `drf_pydantic` and it will use
`Person`'s manually-defined serializer for its `ceo` field.

```python
from drf_pydantic import BaseModel
from rest_framework.serializers import Serializer


class MyCustomSerializer(Serializer):
    name = CharField(allow_null=False, required=True)
    age = IntegerField(allow_null=False, required=True)


class Person(BaseModel):
    name: str
    age: float

    drf_serializer = MyCustomSerializer


class Employee(Person):
    salary: float


class Company(BaseModel):
    ceo: Person
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/georgebv/drf-pydantic",
    "name": "drf-pydantic",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.9,<4.0",
    "maintainer_email": "",
    "keywords": "django,drf,pydantic,typing,rest,api",
    "author": "George Bocharov",
    "author_email": "bocharovgeorgii@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/52/ae/0de731dd3d50ecb77104275bf68b8edc4181046c4994409c5f2902a9f2e9/drf_pydantic-2.2.0.tar.gz",
    "platform": null,
    "description": "<p align=\"center\">\n  <a href=\"https://github.com/georgebv/drf-pydantic/actions/workflows/test.yml\" target=\"_blank\">\n    <img src=\"https://github.com/georgebv/drf-pydantic/actions/workflows/test.yml/badge.svg?event=pull_request\" alt=\"Test Status\">\n  </a>\n  <a href=\"https://codecov.io/gh/georgebv/drf-pydantic\" target=\"_blank\">\n    <img src=\"https://codecov.io/gh/georgebv/drf-pydantic/branch/main/graph/badge.svg?token=GN9rxzIFMc\" alt=\"Test Coverage\"/>\n  </a>\n  <a href=\"https://badge.fury.io/py/drf-pydantic\" target=\"_blank\">\n    <img src=\"https://badge.fury.io/py/drf-pydantic.svg\" alt=\"PyPI version\" height=\"20\">\n  </a>\n</p>\n\n<p align=\"center\">\n  <i>\n    Use pydantic with Django REST framework\n  </i>\n</p>\n\n- [Introduction](#introduction)\n  - [Performance](#performance)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [General](#general)\n  - [Existing Models](#existing-models)\n  - [Nested Models](#nested-models)\n  - [Manual Serializer Configuration](#manual-serializer-configuration)\n    - [Per-Field Configuration](#per-field-configuration)\n    - [Custom Serializer](#custom-serializer)\n\n# Introduction\n\n[Pydantic](https://pydantic-docs.helpmanual.io) is a Python library used to perform\ndata serialization and validation.\n\n[Django REST framework](https://www.django-rest-framework.org) is a framework built\non top of [Django](https://www.djangoproject.com/) used to write REST APIs.\n\nIf you develop DRF APIs and rely on pydantic for data validation/(de)serialization ,\nthen `drf-pydantic` is for you \ud83d\ude0d.\n\n> \u2139\ufe0f **INFO**<br> > `drf_pydantic` supports `pydantic` v2. Due to breaking API changes in `pydantic`\n> v2 support for `pydantic` v1 is available only in `drf_pydantic` 1.\\*.\\*.\n\n## Performance\n\nTranslation between `pydantic` models and `DRF` serializers is done during class\ncreation (e.g., when you first import the model). This means that there will be\nzero impact on the performance of your application\n(server instance or serverless session)\nwhen using `drf_pydantic` while your application is running.\n\n# Installation\n\n```shell\npip install drf-pydantic\n```\n\n# Usage\n\n## General\n\nUse `drf_pydantic.BaseModel` instead of `pydantic.BaseModel` when creating your\nmodels:\n\n```python\nfrom drf_pydantic import BaseModel\n\nclass MyModel(BaseModel):\n    name: str\n    addresses: list[str]\n```\n\n`MyModel.drf_serializer` would be equvalent to the following DRF Serializer class:\n\n```python\nclass MyModelSerializer:\n    name = CharField(allow_null=False, required=True)\n    addresses = ListField(\n        allow_empty=True,\n        allow_null=False,\n        child=CharField(allow_null=False),\n        required=True,\n    )\n```\n\nWhenever you need a DRF serializer you can get it from the model like this:\n\n```python\nmy_value = MyModel.drf_serializer(data={\"name\": \"Van\", addresses: [\"Gym\"]})\nmy_value.is_valid(raise_exception=True)\n```\n\n> \u2139\ufe0f **INFO**<br>\n> Models created using `drf_pydantic` are fully idenditcal to those created by\n> `pydantic`. The only change is the addition of the `drf_serializer` attribute.\n\n## Existing Models\n\nIf you have an existing code base and you would like to add the `drf_serializer`\nattribute only to some of your models, then I have great news \ud83e\udd73 - you can easily\nextend your existing `pydantic` models by adding `drf_pydantic.BaseModel` to the list\nof parent classes of the model you want to extend.\n\nYour existing pydantic models:\n\n```python\nfrom pydantic import BaseModel\n\nclass Pet(BaseModel):\n    name: str\n\nclass Dog(Pet):\n    breed: str\n```\n\nUpdate your `Dog` model and get serializer via the `drf_serializer`:\n\n```python\nfrom drf_pydantic import BaseModel as DRFBaseModel\nfrom pydantic import BaseModel\n\nclass Pet(BaseModel):\n    name: str\n\nclass Dog(DRFBaseModel, Pet):\n    breed: str\n\nDog.drf_serializer\n```\n\n> \u26a0\ufe0f **ATTENTION**<br>\n> Inheritance order is important: `drf_pydantic.BaseModel` must always go before\n> the `pydantic.BaseModel` class.\n\n## Nested Models\n\nIf you have nested models and you want to generate serializer only from one of them,\nyou don't have to update all models - only update the model you need, `drf_pydantic`\nwill generate serializers for all normal nested `pydantic` models for free \ud83e\udd77.\n\n```python\nfrom drf_pydantic import BaseModel as DRFBaseModel\nfrom pydantic import BaseModel\n\nclass Apartment(BaseModel):\n    floor: int\n    tenant: str\n\nclass Building(BaseModel):\n    address: str\n    aparments: list[Apartment]\n\nclass Block(DRFBaseModel):\n    buildings: list[Buildind]\n\nBlock.drf_serializer\n```\n\n## Manual Serializer Configuration\n\nIf `drf_pydantic` does not generate the serializer you need, you can either granularly\nconfigure which DRF serializer fields to use for each pydantic field, or you can\ncreate a custom serializer for the model altogether.\n\n> \u26a0\ufe0f **WARNING**<br>\n> When manually configuring the serializer you are responsible for setting all\n> properties of the fields (e.g., `allow_null`, `required`, `default`, etc.).\n> `drf_pydantic` does not perform any introspection for fields that are manually\n> configured or for any fields if a custom serializer is used.\n\n### Per-Field Configuration\n\n```python\nfrom typing import Annotated\n\nfrom drf_pydantic import BaseModel\nfrom rest_framework.serializers import IntegerField\n\nclass Person(BaseModel):\n    name: str\n    age: Annotated[float, IntegerField(min_value=0, max_value=100)]\n```\n\n### Custom Serializer\n\nIn example below, `Person` will use `MyCustomSerializer` as its drf serializer.\n`Employee` will have its own serializer generated by `drf_pydantic` because it\ndoes not have a user-defined `drf_serializer` attribute (it's never inherited).\n`Company` will have its own serializer generated by `drf_pydantic` and it will use\n`Person`'s manually-defined serializer for its `ceo` field.\n\n```python\nfrom drf_pydantic import BaseModel\nfrom rest_framework.serializers import Serializer\n\n\nclass MyCustomSerializer(Serializer):\n    name = CharField(allow_null=False, required=True)\n    age = IntegerField(allow_null=False, required=True)\n\n\nclass Person(BaseModel):\n    name: str\n    age: float\n\n    drf_serializer = MyCustomSerializer\n\n\nclass Employee(Person):\n    salary: float\n\n\nclass Company(BaseModel):\n    ceo: Person\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Use pydantic with the Django REST framework",
    "version": "2.2.0",
    "project_urls": {
        "Homepage": "https://github.com/georgebv/drf-pydantic",
        "Repository": "https://github.com/georgebv/drf-pydantic"
    },
    "split_keywords": [
        "django",
        "drf",
        "pydantic",
        "typing",
        "rest",
        "api"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "122b5e9f38e568cbc9bcfccda0ed35cd32e725073ecaa882635ebf950118867b",
                "md5": "5f0855d1488ab225a47bb9f0033f531f",
                "sha256": "20f4aa06cf3be7f57acf75055d6fe3ddce57a73f8f2789a6b43b912613d2d583"
            },
            "downloads": -1,
            "filename": "drf_pydantic-2.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5f0855d1488ab225a47bb9f0033f531f",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9,<4.0",
            "size": 9753,
            "upload_time": "2024-02-14T05:00:58",
            "upload_time_iso_8601": "2024-02-14T05:00:58.659945Z",
            "url": "https://files.pythonhosted.org/packages/12/2b/5e9f38e568cbc9bcfccda0ed35cd32e725073ecaa882635ebf950118867b/drf_pydantic-2.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "52ae0de731dd3d50ecb77104275bf68b8edc4181046c4994409c5f2902a9f2e9",
                "md5": "290ea1a9ad1c9930f9e0d89f2a05af8d",
                "sha256": "6fe0dda9e9e8527d06440482de73b8f820e7ea63be3ef5a9480c9c3f5a0d95f3"
            },
            "downloads": -1,
            "filename": "drf_pydantic-2.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "290ea1a9ad1c9930f9e0d89f2a05af8d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9,<4.0",
            "size": 10758,
            "upload_time": "2024-02-14T05:01:00",
            "upload_time_iso_8601": "2024-02-14T05:01:00.256076Z",
            "url": "https://files.pythonhosted.org/packages/52/ae/0de731dd3d50ecb77104275bf68b8edc4181046c4994409c5f2902a9f2e9/drf_pydantic-2.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-14 05:01:00",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "georgebv",
    "github_project": "drf-pydantic",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "drf-pydantic"
}
        
Elapsed time: 0.18339s