Generate goose-style SQL migrations from Django migrations, plus base model mixins
Project description
DJM
Generate SQL migrations from Django models for goose, golang-migrate, SQLx (Rust), or Diesel (Rust). One app: define models in djm, run Django migrations, then export to SQL.
Why
I build a lot of POCs in Django. When one works and needs to turn into something with real business impact, I usually rewrite in Go or Rust. I only want to rewrite the business logic—not waste time turning existing tables into SQL migrations by hand. DJM exports the schema from Django so I can drop it into a Go (goose) or Rust (SQLx, Diesel) project and focus on the code that matters.
Requirements
- Python ≥3.13
- Django ≥6.0
Quick start
pip install djm
djm init myapp
cd myapp
Edit models in djm/models/, then:
pip install -e . # or: uv sync
python manage.py makemigrations djm
python manage.py migrate
python manage.py goose # or: python manage.py sqlx, or: python manage.py diesel
Use the generated SQL with your migration tool (goose, golang-migrate, SQLx, or Diesel).
CLI
| Command | Description |
|---|---|
djm init [path] |
Create a new project (default: current directory). |
djm goose [-o DIR] |
Generate goose-style SQL (default: migrations). |
djm sqlx [-o DIR] |
Generate SQLx-style SQL (default: migrations). |
djm diesel [-o DIR] |
Generate Diesel CLI migrations (default: migrations). |
Run djm goose, djm sqlx, and djm diesel from the project root (where manage.py is).
Project layout (after djm init)
| Path | Purpose |
|---|---|
| djm/ | App for your models; includes goose, sqlx, and diesel management commands. |
| base/ | Abstract mixins: UUIDPrimaryKeyMixin, TimestampsMixin, SoftDeleteMixin, SortNumberMixin. |
| core/ | Django project (settings, urls). |
Generating SQL
Goose (one file per migration, up/down in one file):
python manage.py goose [--output-dir DIR] [--no-sql-extension]
SQLx (sqlx-cli reversible format: .up.sql and .down.sql per migration):
python manage.py sqlx [--output-dir DIR] [--no-sql-extension]
Diesel (Diesel CLI: one subdirectory per migration with up.sql and down.sql):
python manage.py diesel [--output-dir DIR]
Output is migrations/<name>/up.sql and migrations/<name>/down.sql. Use with diesel migration run and diesel migration redo.
All commands default to the same dir (migrations). Each marks the directory so the others won’t overwrite it. Use different --output-dir values if you generate for more than one tool (e.g. goose -o goose_migrations, diesel -o diesel_migrations).
Base mixins
Import from base.models:
- UUIDPrimaryKeyMixin – UUID primary key (
uuid6). - TimestampsMixin –
created,updated. - SoftDeleteMixin –
deleted(nullable datetime). - SortNumberMixin –
order_noand default ordering.
Mixins are abstract; you don’t need base in INSTALLED_APPS unless you add migrations there.
Makefile
From project root:
make help– list targetsmake install– install dependencies (uv sync)make migrate– apply Django migrationsmake goose– generate goose SQL (default:migrations)make sqlx– generate SQLx SQL (default:migrations)make diesel– generate Diesel CLI migrations (default:migrations)make test– run testsmake clean– remove generated SQL and__pycache__make build– build wheel/sdist
Use make goose OUT=dir, make sqlx OUT=dir, or make diesel OUT=dir to override the output directory.
Development
From the repo:
pip install -e .
python manage.py test djm
Notes
- SQL is generated for the database in
settings.DATABASES["default"]. Use PostgreSQL/MySQL in settings if you need that dialect. - Down migrations use Django’s
sqlmigrate --backwardsunder the hood.
Credits
This project was largely built with AI. I wrote only the initial rough version that generated SQL; the rest—SQLx support, refactors, tests, CLI, and docs—came from iterating with AI.
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 djm-0.0.3a0.tar.gz.
File metadata
- Download URL: djm-0.0.3a0.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66ea298187dfc91b549e5e714a67ec9b1c02d5ac9f5fb6497aa11ff6ae87d7d9
|
|
| MD5 |
73aa373578c07bcbd529a770d4eb992b
|
|
| BLAKE2b-256 |
fcf4ae7044a59f94072ae8340cdc220ec0e5e3afad373ac5ff4bcbdb02762f87
|
Provenance
The following attestation bundles were made for djm-0.0.3a0.tar.gz:
Publisher:
publish.yml on dcostersabin/djm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
djm-0.0.3a0.tar.gz -
Subject digest:
66ea298187dfc91b549e5e714a67ec9b1c02d5ac9f5fb6497aa11ff6ae87d7d9 - Sigstore transparency entry: 1010432763
- Sigstore integration time:
-
Permalink:
dcostersabin/djm@e5af5ab8a76525a058e0c8b90331cc5b28a7a136 -
Branch / Tag:
refs/tags/v0.0.3-alpha - Owner: https://github.com/dcostersabin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e5af5ab8a76525a058e0c8b90331cc5b28a7a136 -
Trigger Event:
release
-
Statement type:
File details
Details for the file djm-0.0.3a0-py3-none-any.whl.
File metadata
- Download URL: djm-0.0.3a0-py3-none-any.whl
- Upload date:
- Size: 26.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
40b8e61c79e34ace7fc13c048d053a824cb7ad191ca2cf030373c39e372d45aa
|
|
| MD5 |
4b4cfa4ce0b29ae890dcd18d23fb781b
|
|
| BLAKE2b-256 |
e79f57b820028debf5c8714ee0e7c3a937f4882795ec71500511e59e3847bf5d
|
Provenance
The following attestation bundles were made for djm-0.0.3a0-py3-none-any.whl:
Publisher:
publish.yml on dcostersabin/djm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
djm-0.0.3a0-py3-none-any.whl -
Subject digest:
40b8e61c79e34ace7fc13c048d053a824cb7ad191ca2cf030373c39e372d45aa - Sigstore transparency entry: 1010432793
- Sigstore integration time:
-
Permalink:
dcostersabin/djm@e5af5ab8a76525a058e0c8b90331cc5b28a7a136 -
Branch / Tag:
refs/tags/v0.0.3-alpha - Owner: https://github.com/dcostersabin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e5af5ab8a76525a058e0c8b90331cc5b28a7a136 -
Trigger Event:
release
-
Statement type: