Code Generation (make gen)
Django-CFG provides a unified code generation system that produces type-safe API clients for multiple platforms directly from your Django project. All generation is configured via a single generation.py file at the project root.
Quick Start
make gen # generate all targets
make gen-ts # TypeScript only
make gen-py # Python only
make gen-go # Go only
make gen-web # web targets only
make gen-dry # dry run (preview, no files written)
make gen-list # list all configured targetsOr directly:
python manage.py gen
python manage.py gen --ts
python manage.py gen --target sdk
python manage.py gen --dry-rungeneration.py Config File
Place generation.py at your Django project root (next to manage.py). It exports a single config object:
from pathlib import Path
from django_cfg.modules.django_codegen import (
Config, OpenAPI, Centrifugo, Target, Language, TargetType,
)
ROOT = Path(__file__).parent
FRONTEND = ROOT.parent / "frontend"
# Named path constants for readability
MY_APP = FRONTEND / "apps" / "my" / "app"
MY_API = MY_APP / "_lib" / "api" / "generated"
MY_WS = MY_APP / "_ws" / "generated"
config = Config(
openapi=OpenAPI(targets=[...]),
centrifugo=Centrifugo(targets=[...]),
)Convention: define named path constants before config — this makes it easy to see all output locations at a glance and avoid repetitive / "apps" / "my" / ... chains in every Target.
OpenAPI Clients
Generated from DRF ViewSets via drf-spectacular. Each Target maps a set of API groups to an output directory.
openapi=OpenAPI(
targets=[
# Web frontend
Target(
lang=Language.TYPESCRIPT,
type=TargetType.WEB,
path=MY_API,
groups=["profiles", "workspaces", "machines"],
),
# TypeScript SDK package
Target(
lang=Language.TYPESCRIPT,
type=TargetType.SDK,
path=FRONTEND / "sdk" / "core" / "src" / "api" / "generated",
groups=["machines", "workspaces"],
),
# Python SDK
Target(
lang=Language.PYTHON,
type=TargetType.SDK,
path=PACKAGES / "my_sdk" / "src" / "my_sdk" / "api" / "generated",
groups=["machines"],
),
# Go CLI
Target(
lang=Language.GO,
type="cli",
path=SOFTWARE / "my_go" / "pkg" / "api" / "generated",
groups=["system", "machines"],
),
# Swift iOS
Target(
lang=Language.SWIFT_CODABLE,
type="mobile",
path=SOFTWARE / "MyApp" / "Sources" / "API" / "Generated",
groups=["profiles", "machines"],
),
],
go_module="github.com/myorg/myapp/pkg/api/generated", # optional
),API Groups
Groups correspond to Django apps registered in openapi_client config (in api/config.py):
openapi_client=OpenAPIClientConfig(
groups=[
OpenAPIGroupConfig(name="profiles", apps=["apps.profiles"]),
OpenAPIGroupConfig(name="machines", apps=["apps.machines"]),
],
)Wildcard patterns are supported: "cfg_*" matches all groups starting with cfg_.
Auto-discovered Extensions
For projects with extension packages, use ExtensionTarget to auto-discover them:
from django_cfg.modules.django_codegen import ExtensionTarget
openapi=OpenAPI(
targets=[...],
extensions=ExtensionTarget(
lang=Language.TYPESCRIPT,
frontend_path=FRONTEND / "extensions",
package_pattern="ext-{name}",
output_pattern="src/api/generated",
group_prefix="ext_",
),
),This scans frontend/extensions/ext-*/ and maps each to the ext_{name} API group automatically.
Centrifugo WebSocket Clients
Generated from channel definitions registered via @centrifugo_channel decorator. Output goes to app/_ws/generated/ by convention.
centrifugo=Centrifugo(
targets=[
Target(
lang=Language.TYPESCRIPT,
type=TargetType.WEB,
path=MY_WS,
groups=["terminal", "ai_chat"],
),
],
),Generated files include:
types.ts— TypeScript interfaces for all channel event typesclient.ts— typed API wrapper with one method per RPC endpointrpc-client.ts— base WebSocket RPC clientsubscriptions.ts— typed subscription helpersindex.ts— barrel export
Registering Channels
Channels must be registered in your Django app before generation:
# apps/terminal/channels.py
from django_cfg.apps.integrations.centrifugo.decorators import centrifugo_channel
from apps.terminal.models.events import TerminalEvent
centrifugo_channel(
name="terminal",
pattern="terminal:session:{session_id}",
event_type=TerminalEvent,
)And imported in apps.py:
class TerminalConfig(AppConfig):
def ready(self):
import apps.terminal.channels # noqaTarget Reference
| Field | Type | Description |
|---|---|---|
lang | Language / Platform | Target language: TYPESCRIPT, PYTHON, GO, SWIFT_CODABLE |
type | TargetType / str | Target category: WEB, SDK, ADMIN, PACKAGES, or custom string like "mobile", "cli" |
path | Path | Absolute output directory |
groups | list[str] | API groups to include. Supports "cfg_*" wildcards for OpenAPI |
post_build | str | None | Optional shell command to run after copy, e.g. "pnpm build" |
Config Reference
| Field | Type | Description |
|---|---|---|
openapi | OpenAPI | None | OpenAPI REST client generation config |
centrifugo | Centrifugo | None | Centrifugo WebSocket client generation config |
sdk | SDK | None | SDK packages config |
orm | ORM | None | Django → FastAPI/SQLModel ORM generation |
CLI Flags
| Flag | Description |
|---|---|
--ts | TypeScript targets only |
--py | Python targets only |
--go | Go targets only |
--swift | Swift targets only |
--target <type> | Filter by target type (web, sdk, admin, etc.) |
--groups <g1> <g2> | Filter to specific groups |
--dry-run | Preview what would be generated, no files written |
--list-targets | Print all configured targets and exit |
--verbose | Verbose output |
Real-World Example
Full generation.py from a multi-platform project:
from pathlib import Path
from django_cfg.modules.django_codegen import (
Config, OpenAPI, Centrifugo, Target, Language, TargetType,
)
ROOT = Path(__file__).parent
FRONTEND = ROOT.parent / "frontend"
SOFTWARE = ROOT.parent.parent / "software"
MY_APP = FRONTEND / "apps" / "my" / "app"
MY_API = MY_APP / "_lib" / "api" / "generated"
MY_WS = MY_APP / "_ws" / "generated"
DOCS_API = FRONTEND / "apps" / "docs" / "app" / "_lib" / "api" / "generated"
SDK_CORE = FRONTEND / "sdk" / "core" / "src" / "api" / "generated"
MOBILE_API = SOFTWARE / "MyMobile" / "Sources" / "API" / "Generated"
GO_API = SOFTWARE / "my_go" / "pkg" / "api" / "generated"
PY_SDK = SOFTWARE / "my_sdk" / "python" / "src" / "my_sdk" / "api" / "generated"
config = Config(
centrifugo=Centrifugo(
targets=[
Target(
lang=Language.TYPESCRIPT,
type=TargetType.WEB,
path=MY_WS,
groups=["terminal", "ai_chat"],
),
],
),
openapi=OpenAPI(
go_module="github.com/myorg/myapp/pkg/api/generated",
targets=[
Target(lang=Language.TYPESCRIPT, type=TargetType.WEB, path=MY_API, groups=["profiles", "workspaces", "machines"]),
Target(lang=Language.TYPESCRIPT, type=TargetType.WEB, path=DOCS_API, groups=["site", "reviews"]),
Target(lang=Language.TYPESCRIPT, type=TargetType.SDK, path=SDK_CORE, groups=["machines", "workspaces"]),
Target(lang=Language.SWIFT_CODABLE, type="mobile", path=MOBILE_API, groups=["profiles", "machines"]),
Target(lang=Language.GO, type="cli", path=GO_API, groups=["system", "machines"]),
Target(lang=Language.PYTHON, type=TargetType.SDK, path=PY_SDK, groups=["machines"]),
],
),
)See Also
- Centrifugo Integration — setting up WebSocket channels
- App Design / Serializers — how API groups are defined
- CLI Overview — all available commands