Skip to content

Quick Start

Setup

Add NestedValuesQuerySet as your model's manager:

from django.db import models
from django_nested_values import NestedValuesQuerySet


class Publisher(models.Model):
    name = models.CharField(max_length=100)

    objects = NestedValuesQuerySet.as_manager()


class Author(models.Model):
    name = models.CharField(max_length=100)

    objects = NestedValuesQuerySet.as_manager()


class Book(models.Model):
    title = models.CharField(max_length=200)
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
    authors = models.ManyToManyField(Author, related_name="books")

    objects = NestedValuesQuerySet.as_manager()

With Custom QuerySet

If you have a custom QuerySet, use NestedValuesQuerySetMixin instead:

from django.db.models import QuerySet
from django_nested_values import NestedValuesQuerySetMixin


class BookQuerySet(NestedValuesQuerySetMixin, QuerySet):
    def published(self):
        return self.filter(is_published=True)


class Book(models.Model):
    title = models.CharField(max_length=200)
    is_published = models.BooleanField(default=False)

    objects = BookQuerySet.as_manager()

# Chain custom methods with values_nested()
Book.objects.published().prefetch_related("authors").values_nested()

Ad-hoc Usage (No Model Changes)

Use NestedValuesQuerySet directly without modifying your models:

from django_nested_values import NestedValuesQuerySet

# Instantiate with any model
qs = NestedValuesQuerySet(model=Book)
result = list(
    qs.filter(is_published=True)
    .select_related("publisher")
    .prefetch_related("authors")
    .values_nested()
)

Basic Usage

# Get all fields as nested dicts
books = Book.objects.select_related("publisher").prefetch_related("authors").values_nested()
# [{"id": 1, "title": "...", "publisher": {...}, "authors": [...]}, ...]

# Control which fields with only()
books = Book.objects.only("title").prefetch_related("authors").values_nested()
# [{"id": 1, "title": "...", "authors": [...]}, ...]

For ForeignKey relations, use select_related() for efficient JOINs:

# Efficient: 1 query with JOIN
books = Book.objects.select_related("publisher").values_nested()

# Less efficient: 2 queries (books + publishers)
books = Book.objects.prefetch_related("publisher").values_nested()

Both return the same nested structure:

{"id": 1, "title": "...", "publisher": {"id": 1, "name": "...", "country": "..."}}

ManyToMany and Reverse ForeignKey

For M2M and reverse FK, use prefetch_related():

# ManyToMany
books = Book.objects.prefetch_related("authors").values_nested()
# {"id": 1, "title": "...", "authors": [{"id": 1, "name": "..."}, ...]}

# Reverse ForeignKey
books = Book.objects.prefetch_related("chapters").values_nested()
# {"id": 1, "title": "...", "chapters": [{"id": 1, "title": "Chapter 1"}, ...]}

Use Prefetch objects with only() to control which fields are included:

from django.db.models import Prefetch

# Only fetch author names
books = Book.objects.only("title").prefetch_related(
    Prefetch("authors", queryset=Author.objects.only("name"))
).values_nested()
# {"id": 1, "title": "...", "authors": [{"id": 1, "name": "..."}]}

# Filter prefetched data
books = Book.objects.only("title").prefetch_related(
    Prefetch("authors", queryset=Author.objects.filter(name__startswith="A"))
).values_nested()

# Custom to_attr
books = Book.objects.only("title").prefetch_related(
    Prefetch("chapters", queryset=Chapter.objects.filter(number=1), to_attr="first_chapter")
).values_nested()
# {"id": 1, "title": "...", "first_chapter": [{"id": 1, "title": "Introduction"}]}

Combining Relations

Mix select_related() and prefetch_related():

books = (
    Book.objects
    .only("title")
    .select_related("publisher")           # FK: 1 query with JOIN
    .prefetch_related("authors", "tags")   # M2M: +2 queries
    .values_nested()
)
# Total: 3 queries
# {"id": 1, "title": "...", "publisher": {...}, "authors": [...], "tags": [...]}

Use Case: API Endpoints

The main use case is APIs where data gets passed to Pydantic models:

Approach Flow
Standard Django DB → Django Model → dict → Pydantic
django-nested-values DB → dict → Pydantic
from ninja import NinjaAPI

@api.get("/books", response=list[BookSchema])
def list_books(request):
    return list(
        Book.objects
        .only("id", "title")
        .select_related("publisher")
        .prefetch_related("authors")
        .values_nested()
    )

Benchmark

The included benchmark (benchmarks/benchmark.py) tests fetching 1000 books with multiple relations. Both approaches use the same number of database queries.

uv run python benchmarks/benchmark.py