https://github.com/litestar-org/litestar-django
Django model support for Litestar.
https://github.com/litestar-org/litestar-django
django litestar openapi
Last synced: 11 months ago
JSON representation
Django model support for Litestar.
- Host: GitHub
- URL: https://github.com/litestar-org/litestar-django
- Owner: litestar-org
- License: mit
- Created: 2025-05-02T19:10:37.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-05-19T12:33:15.000Z (about 1 year ago)
- Last Synced: 2025-08-08T09:07:59.668Z (11 months ago)
- Topics: django, litestar, openapi
- Language: Python
- Homepage:
- Size: 195 KB
- Stars: 18
- Watchers: 4
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Litestar-Django
Django model support for Litestar, implemented via Litestar [DTOs](https://docs.litestar.dev/latest/usage/dto/index.html).
```python
from litestar import get, Litestar
from litestar_django import DjangoModelPlugin
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Genre(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
name = models.CharField()
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")
genres = models.ManyToManyField(Genre, related_name="books")
@get("/{author_id:int}")
async def handler(author_id: int) -> Author:
return await Author.objects.prefetch_related("books").aget(id=author_id)
app = Litestar([handler], plugins=[DjangoModelPlugin()])
```
This minimal setup will provide serialization of Django objects returned from handlers,
complete with OpenAPI schema generation.
## Installation
```bash
pip install litestar-django
```
## Usage
### Directly constructing a DTO
```python
from litestar import get
from litestar_django import DjangoModelDTO
from app.models import Author
@get("/{author_id:int}", dto=DjangoModelDTO[Author])
async def handler(author_id: int) -> Author:
return await Author.objects.prefetch_related("books").aget(id=author_id)
```
### Automatically creating DTOs via the plugin
```python
from litestar import get
from litestar_django import DjangoModelPlugin
from app.models import Author
@get("/{author_id:int}")
async def handler(author_id: int) -> Author:
return await Author.objects.prefetch_related("books").aget(id=author_id)
app = Litestar([handler], plugins=[DjangoModelPlugin()])
```
### Creating a model instance from a DTO
```python
from typing import Annotated
from litestar import post
from litestar.dto import DTOConfig
from litestar_django import DjangoModelDTO
from app.models import Author
@post(
"/",
sync_to_thread=True,
dto=DjangoModelDTO[
Annotated[
Author,
# exclude primary key and relationship fields
DTOConfig(exclude={"id", "books"})
]
],
return_dto=DjangoModelDTO[Author],
)
async def handler(data: Author) -> Author:
await data.asave()
return data
```
## OpenAPI
Full OpenAPI schemas are generated from models based on their field types:
### Type map
| Field | OpenAPI type | OpenAPI format |
|------------------------|--------------|----------------|
| `models.JSONField` | `{}` | |
| `models.DecimalField` | `number` | |
| `models.DateTimeField` | `string` | `date-time` |
| `models.DateField` | `string` | `date` |
| `models.TimeField` | `string` | `duration` |
| `models.DurationField` | `string` | `duration` |
| `models.FileField` | `string` | |
| `models.FilePathField` | `string` | |
| `models.UUIDField` | `string` | `uuid` |
| `models.IntegerField` | `integer` | |
| `models.FloatField` | `number` | |
| `models.BooleanField` | `boolean` | |
| `models.CharField` | `string` | |
| `models.TextField` | `string` | |
| `models.BinaryField` | `string` | `byte` |
### Additional properties
The following properties are extracted from fields, in addition to its type:
| OpenAPI property | From |
|--------------------|----------------------|
| `title` | `Field.verbose_name` |
| `description` | `Field.help_text` |
| `enum` | `Field.choices` |
| `exclusiveMinimum` | `MinValueValidator` |
| `exclusiveMaximum` | `MaxValueValidator` |
| `minLength` | `MinLengthValidator` |
| `maxLength` | `MaxLengthValidator` |
### Relationships
Relationships will be represented as individual components, referenced in the schema.
## Lazy loading
> [!IMPORTANT]
> Since lazy-loading is not supported in an async context, you must ensure to always
> load everything consumed by the DTO. Not doing so will result in a
> [`SynchronousOnlyOperation`](https://docs.djangoproject.com/en/5.2/ref/exceptions/#django.core.exceptions.SynchronousOnlyOperation)
> exception being raised by Django
This can be mitigated by:
1. Setting `include` or `exclude` rules to only include necessary fields ([docs](https://docs.litestar.dev/latest/usage/dto/1-abstract-dto.html#excluding-fields))
2. Configuring nested relationships with an appropriate `max_nexted_depth`
([docs](https://docs.litestar.dev/latest/usage/dto/1-abstract-dto.html#nested-fields))
3. Using [`select_related`](https://docs.djangoproject.com/en/5.2/ref/models/querysets/#select-related)
and [`prefetch_related`](https://docs.djangoproject.com/en/5.2/ref/models/querysets/#prefetch-related)
to ensure relationships are fully loaded
## Foreign keys
When defining a `ForeignKey` field, Django will implicitly generate another field on the
model with an `_id` suffix, to store the actual foreign key value. The DTO will include
these implicit fields.
```python
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
name = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")
```
In this example, the DTO for `Book` includes the field definitions
- `id: int`
- `name: str`
- `author_id: int`
- `author: Author`
## Serialization / validation of 3rd party field types
Additionally, the following 3rd party fields / types are supported if the
`DjangoModelPlugin` is installed:
- `django-enumfields`
- `django-enumfields2`
## Contributing
All [Litestar Organization][litestar-org] projects are open for contributions of any
size and form.
If you have any questions, reach out to us on [Discord][discord] or our org-wide
[GitHub discussions][litestar-discussions] page.
An official Litestar Organization Project
[litestar-org]: https://github.com/litestar-org
[discord]: https://discord.gg/litestar
[litestar-discussions]: https://github.com/orgs/litestar-org/discussions