Skip to main content

Command Palette

Search for a command to run...

Best File Structure for Django REST Framework (DRF) Projects

Organize Your DRF Project Like a Senior Developer: Scalable, Async/Async, AI-Ready, and Dockerized

Updated
4 min read
Best File Structure for Django REST Framework (DRF) Projects

When building professional-grade Django REST Framework (DRF) projects, having a clean, maintainable file structure is essential. A proper structure allows you to scale your app, integrate AI/ML, async tasks, hooks, and even containerize it with Docker for deployment.

Here’s the ultimate guide for a senior-developer-ready DRF project structure:

my_project/
│
├── manage.py
├── requirements.txt
├── pyproject.toml / poetry.lock
├── .env                        # Environment variables
├── Dockerfile                  # For containerization
├── docker-compose.yml          # Optional for multi-service setup
│
├── config/                     # Project-level settings
│   ├── __init__.py
│   ├── settings.py             # Base settings
│   ├── settings_dev.py         # Development
│   ├── settings_prod.py        # Production
│   ├── urls.py                 # Root routing
│   ├── asgi.py                 # Async support
│   └── wsgi.py                 # Sync support
│
├── apps/                       # All Django apps live here
│   ├── __init__.py
│   ├── users/                  # Authentication, user management
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── serializers.py
│   │   ├── views.py
│   │   ├── urls.py
│   │   ├── permissions.py
│   │   └── signals.py          # Hooks
│   │
│   ├── ai/                     # AI/ML integration
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── serializers.py
│   │   ├── views.py
│   │   ├── services.py         # AI inference logic
│   │   └── tasks.py            # Async tasks (Celery/RQ)
│   │
│   ├── core/                   # Shared utilities
│   │   ├── __init__.py
│   │   ├── utils.py
│   │   ├── mixins.py
│   │   ├── decorators.py
│   │   └── exceptions.py
│   │
│   └── other_apps/...
│
├── scripts/                    # CLI scripts, data migration, seeding
│   ├── seed_db.py
│   └── cleanup.py
│
├── tasks/                      # Background tasks (Celery/RQ)
│   ├── __init__.py
│   └── ai_tasks.py
│
├── static/                     # Collected static files
├── media/                      # Uploaded files
├── templates/                  # Optional: browsable API or email templates
└── logs/                       # Application logs

Folder-by-Folder Explanation:

1. config/

  • Contains settings, URLs, ASGI/WGI.

  • Environment separation: dev, prod, staging.

  • ASGI for async views and WebSockets.

2. apps/

  • Each app is modular: users, AI, payments, etc.

  • Keeps business logic separate from routes.

AI app example:

  • services.py → business logic

  • tasks.py → background async tasks

  • views.py → API endpoints

  • Async view example:

      from rest_framework.views import APIView
      from rest_framework.response import Response
      from .tasks import async_inference
    
      class PredictView(APIView):
          async def post(self, request):
              data = request.data
              task = async_inference.delay(data)
              return Response({"task_id": task.id})
    

3. signals.py

  • Contains hooks for post_save, pre_save, notifications, logging.

  •   from django.db.models.signals import post_save
      from django.dispatch import receiver
      from .models import User
    
      @receiver(post_save, sender=User)
      def send_welcome_email(sender, instance, created, **kwargs):
          if created:
              print(f"Send email to {instance.email}")
    

4. scripts/

  • For CLI tasks like DB seeding, cleanup, batch updates.

      # scripts/seed_db.py
      import os
      import django
      from faker import Faker
    
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings_dev")
      django.setup()
    
      from apps.users.models import User
      fake = Faker()
    
      def seed_users(n=100):
          for _ in range(n):
              User.objects.create(username=fake.user_name(), email=fake.email(), is_active=True)
          print(f"{n} users created!")
    
      if __name__ == "__main__":
          seed_users()
    

5. Static, Media, Templates

  • static/ → CSS, JS, images for front-end or admin

  • media/ → uploaded files

  • templates/ → optional HTML for emails or browsable API

  • Senior developers collect static files with:

python manage.py collectstatic

6. Docker Integration

Dockerfile:

FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"]

docker-compose.yml:

version: "3.9"

services:
  web:
    build: .
    ports:
      - "8000:8000"
    env_file:
      - .env
    volumes:
      - .:/app
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"
  • Benefits: easy deployment, dev/prod parity, isolated services

7. Why This Structure Works

  • Modular apps → easier collaboration

  • Async ready → WebSockets, background tasks, AI inference

  • Scripts → DB seeding, cleanup, batch jobs

  • Static/Media management → clean separation of assets

  • Dockerized → production-ready

  • Core utilities → DRY principle, reusable code

  • Hooks/Signals → maintainable event-driven logic


Bonus Tips

  1. Version APIs → urls/v1/, urls/v2/

  2. Use pytest for tests inside each app

  3. Keep .env secret keys separate

  4. Separate Celery workers for AI or CPU-heavy tasks


Conclusion

A well-structured DRF project is critical for maintainability, scalability, and performance. This structure allows you to:

  • Integrate AI/ML

  • Handle async workflows efficiently

  • Maintain hooks/signals cleanly

  • Manage static and media files

  • Deploy seamlessly with Docker

Following this structure will make your project production-ready, collaboration-friendly, and easy to maintain, just like senior developers do.