Skip to content

Bidirectional generation

How to generate static Django models and convert bidirectionally

This guide shows how to turn several source types into static Django models and convert data back and forth: - Pydantic ⇄ Django - Dataclass ⇄ Django - TypedClass ⇄ Django - XML Schema ⇄ Django/XML - Django ⇄ Pydantic (dynamic at runtime)

All generators write a single generated_models.py that contains Django model classes and convenience helpers. See templates in src/pydantic2django/django/templates/ for the rendered structure.

Prerequisites

  • Configure Django before using any generator (minimal example shown below).
  • Python 3.11+, Pydantic v2, Poetry/pytest per project guidelines.
import django
from django.conf import settings

if not settings.configured:
    settings.configure(
        INSTALLED_APPS=[
            "django.contrib.contenttypes",
            "django.contrib.auth",
            # Add your app label if needed
        ],
        DATABASES={
            "default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"},
        },
        DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
    )
    django.setup()

Pydantic ⇄ Django

Use StaticPydanticModelGenerator to scan packages for BaseModel classes and generate static Django models. Generated classes inherit Pydantic2DjangoBaseClass and include helpers like .from_pydantic(...) and .to_pydantic(...).

from pydantic import BaseModel, Field
from pydantic2django.pydantic.generator import StaticPydanticModelGenerator

# 1) Generate static Django models from your Pydantic package
gen = StaticPydanticModelGenerator(
    output_path="generated_models.py",
    packages=["your_pydantic_pkg"],
    app_label="your_app",
    filter_function=None,  # or a callable to include/exclude models
    module_mappings={"__main__": "your_app.models"},  # optional import fixups
    verbose=True,
)
gen.generate()

# 2) Use the generated models
from your_pydantic_pkg import User as PydUser
from generated_models import DjangoUser  # class name prefixed; see output

p = PydUser(id=1, email="john@example.com", name="John")
dj = DjangoUser.from_pydantic(p)
dj.save()

# Convert back
round_trip = dj.to_pydantic()

Notes: - Choices map to Literal[...] in Pydantic with original choices preserved in json_schema_extra. - Relationships, JSON, auto PKs, and file/image fields are handled by the bidirectional mapper.


Dataclass ⇄ Django

Use DataclassDjangoModelGenerator to generate static Django models from Python dataclasses. Generated classes inherit Dataclass2DjangoBaseClass and include .from_dataclass(...) and .to_dataclass(...).

import dataclasses
from pydantic2django.dataclass.generator import DataclassDjangoModelGenerator

@dataclasses.dataclass
class Person:
    id: int
    name: str

gen = DataclassDjangoModelGenerator(
    output_path="generated_models.py",
    app_label="dc_app",
    packages=["your_dc_pkg"],
    filter_function=lambda cls: dataclasses.is_dataclass(cls),
    verbose=True,
)
gen.generate()

from your_dc_pkg import Person as DCPerson
from generated_models import DjangoPerson

dc = DCPerson(id=1, name="Ada")
dj = DjangoPerson.from_dataclass(dc)
dj.save()

back = dj.to_dataclass()

TypedClass ⇄ Django

Use TypedClassDjangoModelGenerator for plain Python classes with type hints you want to map to Django fields. Generated classes inherit TypedClass2DjangoBaseClass and include .from_typedclass(...) and .to_typedclass(...).

from pydantic2django.typedclass.generator import TypedClassDjangoModelGenerator

class Settings:
    def __init__(self, retries: int, region: str):
        self.retries = retries
        self.region = region

gen = TypedClassDjangoModelGenerator(
    output_path="generated_models.py",
    app_label="typed_app",
    packages=["your_typed_pkg"],
    filter_function=None,
    verbose=True,
)
gen.generate()

from generated_models import DjangoSettings

cfg = Settings(retries=3, region="us-east-1")
dj = DjangoSettings.from_typedclass(cfg)
dj.save()

restored = dj.to_typedclass()

XML Schema ⇄ Django/XML

Use XmlSchemaDjangoModelGenerator to parse .xsd files and generate static Django models that inherit Xml2DjangoBaseClass. These provide XML-focused helpers like .from_xml_dict(...), .to_xml_dict(...) and .to_xml_string(...).

from pydantic2django.xmlschema.generator import XmlSchemaDjangoModelGenerator

gen = XmlSchemaDjangoModelGenerator(
    schema_files=["tests/xmlschema/fixtures/simple_schema.xsd"],
    output_path="generated_models.py",
    app_label="xsd_app",
    nested_relationship_strategy="auto",  # "fk" | "json" | "auto"
    list_relationship_style="child_fk",   # "child_fk" | "m2m" | "json"
    verbose=True,
)
gen.generate()

from generated_models import Address  # example class from the schema

addr = Address.from_xml_dict({"street": "123 Main", "zipCode": "94107"})
xml = addr.to_xml_string()

Django ⇄ Pydantic (dynamic)

To project a Django model to a Pydantic model (and back) at runtime, use DjangoPydanticConverter. This does not write static files; it generates a Pydantic model class on the fly using the same bidirectional mapper.

from pydantic2django.django.conversion import DjangoPydanticConverter
from your_django_app.models import User

conv = DjangoPydanticConverter(User)
PydUser = conv.generated_pydantic_model

u = User.objects.get(pk=1)
p = conv.to_pydantic(u)

# Modify and persist back
u2 = conv.to_django(p)  # updates or creates

Common options and tips

  • Filtering: filter_function lets you keep only specific source models.
  • Import fixes: module_mappings rewrites imports (e.g., replace __main__ with your_app.models).
  • Relationships: Pydantic/Dataclass/TypedClass generators resolve dependencies and order automatically.
  • Context fields: Pydantic-only context values are surfaced via generated context classes; pass them when calling .to_pydantic(...) if required by your model.
  • Templates: Jinja2 templates under django/templates/ control the generated file layout.