Convert Various non-Django models to Django models dynamically
Project description
Pydantic2Django: The Bridge Between Python Objects and the Django ORM
A powerful utility for generating Django models from Pydantic models, Python dataclasses, and even generic Python classes, and providing seamless, bidirectional data conversion between them.
[!IMPORTANT] Namespace rename and deprecation: The distribution is now published as
django-typed2djangoand the new import namespace istyped2django. The oldpydantic2djangonamespace is deprecated and will be removed in version 1.1.0. Please migrate imports frompydantic2django.*totyped2django.*.
Overview
Pydantic2Django bridges the gap between your application's data layer (defined using Pydantic, dataclasses, etc.) and your persistence layer in Django. It allows you to:
- Generate
models.pyfiles automatically from your existing Python classes. - Convert data seamlessly between Django model instances and your source Pydantic/dataclass objects.
- Persist and manage application data objects in a Django database without writing boilerplate mapping code.
- Handle relationships between your Python objects and translate them into Django's relational fields (
ForeignKey,ManyToManyField).
This library supports:
- Pydantic Models: Robust support for
pydantic.BaseModel. - Python Dataclasses: Full support for classes decorated with
@dataclasses.dataclass. - Generic Python Classes: Experimental support for converting plain Python classes that act as data containers (see Experimental Features).
Core Features
- Automatic Django Model Generation: Scans your project to discover data classes and generates a complete, ready-to-use
models.pyfile. - Bidirectional Data Mapping: The generated Django models, or models inheriting from the provided base classes, include methods like
.from_pydantic()and.to_pydantic()for easy and reliable data conversion. - Relationship Management: Intelligently detects relationships between your source models and automatically creates the corresponding
ForeignKeyandManyToManyFieldfields in Django. - Timescale-aware Generation (optional): Provides heuristics and safe wiring for TimescaleDB so hypertables never use illegal hypertable→hypertable FKs (replaced with indexed soft references), while preserving legal FK patterns.
- Type Hint Aware: Leverages type hints to create the most appropriate Django model fields, including support for
Optional,Union,Literal, and generic collections. - Extensible & Modular: The library is structured into distinct modules for
pydantic,dataclass, andtypedclasshandling, allowing for clear separation of concerns. You can dive into the core logic insrc/pydantic2django/core/.
Full Documentation
For the complete documentation site, visit the GitHub Pages deployment: pydantic2django docs.
Alternatives
Consider django-pydantic-field which has lots of cool features but not quite as much scope (and, commensurately, not as much complexity) as this library.
Installation
pip install django-typed2django
How It Works
Pydantic2Django operates using a three-stage pipeline:
- Discovery: It scans specified Python packages to find and identify source models (Pydantic, dataclass, etc.).
- Factory: For each discovered model, it analyzes its fields, type hints, and relationships to create an in-memory representation of a Django model.
- Generator: It uses the in-memory representation and Jinja2 templates to generate the final Python code for your
models.pyfile, including all necessary imports, model classes, and field definitions.
Usage
Example 1: Generating a models.py File
The most common use case is to generate a Django models.py file from your existing Pydantic models or dataclasses.
Let's say you have Pydantic models in my_app/pydantic_models.py:
# my_app/pydantic_models.py
import uuid
from pydantic import BaseModel, Field
class User(BaseModel):
id: uuid.UUID = Field(default_factory=uuid.uuid4)
name: str
email: str
class Product(BaseModel):
id: uuid.UUID = Field(default_factory=uuid.uuid4)
name: str
price: float
owner: User
You can generate the Django models with a simple script:
# scripts/generate_django_models.py
from typed2django.pydantic.generator import StaticPydanticModelGenerator
# Create a generator for Pydantic models
generator = StaticPydanticModelGenerator(
output_path="my_app/models.py",
packages=["my_app.pydantic_models"],
app_label="my_app",
verbose=True
)
# Generate the models file
generator.generate_models_file()
print("Django models generated successfully!")
This will create my_app/models.py containing User and Product Django models, complete with a ForeignKey relationship.
Note: For dataclasses, you would use
DataclassDjangoModelGeneratorfromtyped2django.dataclass.
Example 2: Using the Generated Models
The generated models inherit from a base class that provides helpful conversion methods.
# my_app/views.py
from my_app.models import User as DjangoUser
from my_app.pydantic_models import User as PydanticUser
# Assume you get a Pydantic object from an API call
pydantic_user = PydanticUser(name="Jane Doe", email="jane.doe@example.com")
# 1. Create a new Django model instance from the Pydantic object
django_user = DjangoUser.from_pydantic(pydantic_user)
django_user.save()
# 2. Retrieve a Django object and convert it back to a Pydantic object
retrieved_user = DjangoUser.objects.get(name="Jane Doe")
pydantic_version = retrieved_user.to_pydantic()
assert pydantic_version.name == "Jane Doe"
This bidirectional conversion makes it trivial to move data between your application logic and the database.
Advanced Usage
Filtering Models
You can provide a filter_function to the generator to selectively include or exclude models from the generation process.
def user_only_filter(model):
"""Only include models with names containing 'User'"""
return "User" in model.__name__
generator = StaticPydanticModelGenerator(
# ... other args
filter_function=user_only_filter,
)
TimescaleDB Integration (Optional)
Pydantic2Django can help you generate models that follow TimescaleDB’s constraints and best practices.
-
Safe FK policy
- Hypertable → Dimension: FK allowed.
- Dimension → Dimension: FK allowed.
- Hypertable → Hypertable: Not allowed by TimescaleDB. The generator replaces these with an indexed soft reference field (e.g.,
UUIDField(db_index=True, null=True, blank=True)), leaving referential checks to the application/background jobs.
-
Heuristics to classify hypertables vs dimensions (XML path)
- Classified by signals like: presence of time/timestamp/sequence fields; unbounded list growth; event/observation-like names (e.g.,
Samples,Events,Condition); negative weight for definition/metadata types (e.g.,*Definition*,*Parameters*,Header). - The XML generator chooses a per-model base:
- Hypertable types use
pydantic2django.django.timescale.bases.XmlTimescaleBase. - Dimension types use
pydantic2django.django.models.Xml2DjangoBaseClass.
- Hypertable types use
- Illegal hypertable→hypertable relations are automatically converted to soft references.
- Classified by signals like: presence of time/timestamp/sequence fields; unbounded list growth; event/observation-like names (e.g.,
-
Using Timescale bases in other paths
- Pydantic and Dataclass paths can opt-in by setting the base explicitly before generation:
from pydantic import BaseModel
from pydantic2django.django.timescale.bases import PydanticTimescaleBase
from pydantic2django.pydantic.generator import StaticPydanticModelGenerator
class SampleObservation(BaseModel):
device_id: str
timestamp: int
value: float
gen = StaticPydanticModelGenerator(output_path="models.py", packages=["my_pkg"], app_label="my_app")
# Force Timescale-enabled base for generated models (treat as hypertables)
gen.base_model_class = PydanticTimescaleBase
gen.generate_models_file()
For XML schemas, Timescale handling is automatic via heuristics. For non-XML paths, choose a Timescale base where appropriate.
Experimental Features
Generic Python Class Conversion
The library includes an experimental generator for converting plain Python classes into Django models, located in src/pydantic2django/typedclass/. This is useful for persisting configuration objects or instances of classes from third-party libraries.
Due to its experimental nature, it relies heavily on clear type hints in __init__ and may require manual adjustments to the generated code. You can read more about its goals and limitations in the TypedClass README.
Testing
Run the tests with:
uv run pytest -q
Contributing
Contributions are welcome! Please read the contributing guide: CONTRIBUTING.md.
- All pull requests must pass the full test suite locally and in CI to demonstrate no regressions, or include a clear explanation for why automated tests are not appropriate for the change (with manual validation steps or rationale).
- Aim to maintain backward compatibility, keep dependencies minimal, and follow PEP 8 with type hints.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_typed2django-1.0.20.tar.gz.
File metadata
- Download URL: django_typed2django-1.0.20.tar.gz
- Upload date:
- Size: 789.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8882dfca9e986bf2297b765f43d3c02e1ef473010b33570c49c00a447268870b
|
|
| MD5 |
abf5357a931ff0c58efbcd2f40dc43ea
|
|
| BLAKE2b-256 |
04d0a98d3df44f7e568edae87b5f37a98dc50ad6970a2a82a4c5fe6573c99526
|
Provenance
The following attestation bundles were made for django_typed2django-1.0.20.tar.gz:
Publisher:
publish-pypi.yml on billthefighter/pydantic2django
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_typed2django-1.0.20.tar.gz -
Subject digest:
8882dfca9e986bf2297b765f43d3c02e1ef473010b33570c49c00a447268870b - Sigstore transparency entry: 583332246
- Sigstore integration time:
-
Permalink:
billthefighter/pydantic2django@e50df13850feb428c93de37dd47953829609ac19 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/billthefighter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@e50df13850feb428c93de37dd47953829609ac19 -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_typed2django-1.0.20-py3-none-any.whl.
File metadata
- Download URL: django_typed2django-1.0.20-py3-none-any.whl
- Upload date:
- Size: 210.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0dedbaf69baf59a1a89d09b2adb9b0bb08f05c1b0f77d02afe5ecab79597e1f1
|
|
| MD5 |
c3ff3d3abfeb52da27259ea25f34511b
|
|
| BLAKE2b-256 |
1bf2478641f4f054cbee4d3aeebe1bdc44753a875cd557bafb504ddae0e3dfa8
|
Provenance
The following attestation bundles were made for django_typed2django-1.0.20-py3-none-any.whl:
Publisher:
publish-pypi.yml on billthefighter/pydantic2django
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_typed2django-1.0.20-py3-none-any.whl -
Subject digest:
0dedbaf69baf59a1a89d09b2adb9b0bb08f05c1b0f77d02afe5ecab79597e1f1 - Sigstore transparency entry: 583332254
- Sigstore integration time:
-
Permalink:
billthefighter/pydantic2django@e50df13850feb428c93de37dd47953829609ac19 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/billthefighter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@e50df13850feb428c93de37dd47953829609ac19 -
Trigger Event:
push
-
Statement type: