Skip to Content
GuidesApp Design GuideApp Structure

App Structure

Every django-cfg app follows a layered architecture with clear separation of concerns.

Standard Layout

my_app/ ├── models/ │ ├── __init__.py # Re-exports all models │ ├── my_model.py │ └── choices.py # TextChoices enums ├── managers/ │ ├── __init__.py │ └── my_model_managers.py # Custom QuerySet + Manager ├── services/ │ ├── __init__.py │ └── my_service.py # Business logic ├── views/ │ ├── api/ │ │ ├── __init__.py │ │ └── my_viewsets.py # DRF ViewSets │ └── serializers/ │ ├── __init__.py │ └── my_serializers.py # DRF Serializers ├── admin/ │ ├── __init__.py │ ├── my_admin.py # PydanticAdmin config │ └── actions.py # Admin actions ├── tasks/ │ ├── __init__.py │ └── process_task.py # Background tasks (RQ/Dramatiq) ├── tests/ │ ├── __init__.py │ ├── conftest.py # Fixtures │ ├── factories.py # Model factories │ ├── test_models.py │ └── test_services.py ├── management/ │ └── commands/ │ └── my_command.py # Management commands ├── migrations/ ├── apps.py ├── urls.py # DRF router └── signals.py # Django signals (if needed)

When to Use Files vs Directories

Single file — simple apps

If an app has 1-2 models and straightforward logic, use flat files:

activity/ ├── models.py # Single model ├── admin.py # Single admin class ├── urls.py └── views/ ├── api/ │ └── activity_viewsets.py └── serializers/ └── activity_serializers.py

Real example: the activity app (cmdop) is a simple audit logger — one model, one read-only ViewSet, one serializer.

Directory — complex apps

When a file exceeds ~300 lines or has multiple related classes, split into a directory with __init__.py re-exports:

# models/__init__.py from .download_request import DownloadRequest from .download_segment import DownloadSegment from .download_error import DownloadError from .export_job import ExportJob

Real example: cryptodb_driver (stockapis) has 4 models, 8 services, 5 task files — everything is in directories.

File Size Limits

File typeMax linesNotes
Production code500Excluding comments and docstrings
Complex logic (models, services)300Split into multiple files if exceeded
Configuration files200Admin configs, app configs
Test files400Per test file
Test classes150Per class within a file

When a file approaches the limit, decompose it — don’t compress code to fit. Create a directory with focused files instead.

Layer Flow

Request → URLs → ViewSet → Serializer → Service → Manager → Model → DB ↑ ↑ (validation) (query logic)

Each layer has a single responsibility:

LayerResponsibilityImports from
ModelsSchema, constraints, propertiesNothing (bottom layer)
ManagersQuery composition, chainable filtersModels
ServicesBusiness logic, transactions, external APIsModels, Managers
SerializersValidation, field mapping, formattingModels
ViewSetsHTTP handling, permissions, routingSerializers, Services
AdminAdmin UI configurationModels

Key rule: ViewSets should never contain business logic. They orchestrate: validate input (serializer) → call service → serialize output.

App Registration

All django-cfg apps are registered through the core builder — never in local project configs:

# django_cfg/core/builders/apps_builder.py apps.append("django_cfg.apps.system.my_app") # ✅ Correct # django_cfg/apps/urls.py path('cfg/my-app/', include('django_cfg.apps.system.my_app.urls')) # ✅ Correct

Naming Conventions

EntityPatternExample
App directorysnake_caseapi_keys, cryptodb_driver
Model classPascalCaseDownloadRequest, WorkspaceMember
Manager{Model}ManagerMachineManager, AgentManager
QuerySet{Model}QuerySetMachineQuerySet
ViewSet{Model}ViewSetSymbolViewSet, ActivityViewSet
Serializer{Model}{Action}SerializerAgentListSerializer, APIKeyCreateSerializer
Service{Feature}ServiceSyncService, ConfidenceService
Task function{verb}_{noun}_tasksync_all_symbols_task
URL basenamesnake_casebasename='api-key'

Checklist for New Apps

  • Choose flat files or directories based on complexity
  • Create models with proper constraints and indexes
  • Add custom managers for common query patterns
  • Implement services for business logic
  • Create ViewSet with @extend_schema decorators
  • Write separate serializers per action (List, Detail, Create)
  • Configure admin with PydanticAdmin + AdminConfig
  • Register app in apps_builder.py
  • Register URLs in django_cfg/apps/urls.py
  • Write tests (models + services)
  • Create and apply migrations
Last updated on