From python-experts
Sets up Django 6.0 project with uv, direnv, HTMX, OAuth, DRF, Pydantic, pytest, mypy, ruff, Docker PostgreSQL or Supabase, custom user model, and full type annotations. Use for production-ready Django from scratch.
How this skill is triggered — by the user, by Claude, or both
Slash command
/python-experts:django-project-setupThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Automated setup for production-ready Django 6.0 projects with modern tooling.
README.mdexamples/fully-typed-model.mdexamples/htmx-example.mdexamples/testing-example.mdexamples/type-checking-example.mdexamples/uuid-model-example.mdtemplates/CLAUDE.md.templatetemplates/Makefile.templatetemplates/config-urls.py.templatetemplates/conftest.py.templatetemplates/core-admin.py.templatetemplates/core-apps.py.templatetemplates/core-factories.py.templatetemplates/core-models.py.templatetemplates/core-test-models.py.templatetemplates/docker-compose.yml.templatetemplates/pyproject-tools.toml.templatetemplates/pytest.ini.templatetemplates/settings-base.py.templatetemplates/settings-dev.py.templateAutomated setup for production-ready Django 6.0 projects with modern tooling.
Creates a complete Django 6.0 project with:
This project template is optimized for AI coding assistants:
disallow_untyped_defs = true enforced from day 1Compatible with: GitHub Copilot, Cursor, Cody, Continue, Tabnine, and other AI coding assistants.
When you provide full type annotations:
{project_name}/
├── config/ # Settings and core config
│ ├── settings/
│ │ ├── __init__.py
│ │ ├── base.py # Core settings
│ │ ├── dev.py # Development
│ │ └── prod.py # Production
│ ├── urls.py
│ ├── asgi.py
│ └── wsgi.py
├── apps/ # Django apps
│ ├── __init__.py
│ └── core/ # Shared utilities
│ ├── models.py # UUIDModel base class
│ └── ...
├── templates/ # Global templates
├── static/ # Global static files
├── pyproject.toml # uv dependencies
├── pytest.ini # Test configuration
├── conftest.py # Test fixtures
├── docker-compose.yml # PostgreSQL container
├── Makefile # Development commands
├── .envrc # Environment config
├── .env.example # Environment template
├── manage.py
└── CLAUDE.md # Project instructions
# With Docker PostgreSQL (default)
/django-project-setup myproject
# With Supabase
/django-project-setup myproject --with-supabase
The skill will:
# Start PostgreSQL
/usr/bin/make start-docker
# Run migrations
/usr/bin/make migrate
# Create superuser (set password in .envrc.local first)
/usr/bin/make createsuperuser
# Start development server
/usr/bin/make runserver
# Run tests
/usr/bin/make test
# Type checking
/usr/bin/make typecheck
# Linting
/usr/bin/make lint
Visit http://localhost:8000/admin/ to verify setup.
# 1. Complete Supabase setup (see SUPABASE_SETUP.md)
# 2. Add DATABASE_URL to .env.local
# 3. Allow direnv
direnv allow
# Run migrations
uv run python manage.py migrate
# Create superuser
uv run python manage.py createsuperuser
# Start development server
uv run python manage.py runserver
# Run tests
uv run pytest
# Type checking
uv run mypy .
# Linting
uv run ruff check .
Visit http://localhost:8000/admin/ to verify setup.
When this skill is invoked with a project name (e.g., /django-project-setup myproject or /django-project-setup myproject --with-supabase), follow these steps:
Parse Arguments:
# Extract project name (first non-flag argument)
# Check if --with-supabase flag is present
# Set use_supabase=true if flag found, false otherwise
Check if uv is installed, install if missing:
which uv || curl -LsSf https://astral.sh/uv/install.sh | sh
Check if Python 3.12+ is available, install via uv if missing:
# Check current Python version
python3 --version 2>/dev/null | grep -q "Python 3.1[2-9]" || \
# If not found, use uv to install Python 3.12
uv python install 3.12
Verify current directory or use /tmp if not specified
Step 1: Ask for First App Name
Use AskUserQuestion to ask:
Question: "What should be the first Django app to create?"
Options:
- "blog" (description: "Blog/content management app")
- "accounts" (description: "User accounts and profiles")
- "api" (description: "API endpoints")
- "core" (description: "Core functionality only")
Header: "First App"
Step 2: Initialize uv Project
# Initialize project with Python 3.12+
uv init --python 3.12 {project_name}
builtin cd {project_name}
# Verify .python-version file was created
[ -f .python-version ] && echo "✅ Python version pinned" || echo "3.12" > .python-version
Step 3: Add Core Dependencies
uv add django psycopg[binary] django-environ
uv add djangorestframework django-oauth-toolkit django-htmx pydantic
uv add --group dev pytest pytest-django pytest-cov pytest-asyncio
uv add --group dev factory-boy pytest-factoryboy
uv add --group dev mypy django-stubs types-requests
uv add --group dev ruff django-extensions ipython
Step 4: Create Django Project Structure
uv run django-admin startproject config .
Step 5: Create Directory Structure
mkdir -p apps/core/{migrations,tests}
mkdir -p apps/{first_app_name}/{migrations,tests}
mkdir -p templates/partials
mkdir -p static
mkdir -p config/settings
Step 6: Create Configuration Files
Use the templates in templates/ directory to create:
Makefile - Use Makefile.template (conditionally add Docker targets if use_supabase == false).envrc - Use .envrc.template, configure DATABASE_URL based on use_supabase.env - Use .env.template, configure database variables based on use_supabase.env.example - Use .env.example.template, configure based on use_supabase.envrc.local - Use .envrc.local.template.gitignore - Use .gitignore.templatepytest.ini - Use pytest.ini.templateconftest.py - Use conftest.py.templateCLAUDE.md - Use CLAUDE.md.template, replace {project_name} and add database-specific notesIf use_supabase == false (Docker):
docker-compose.yml - Use docker-compose.yml.template, replace {project_name}If use_supabase == true:
SUPABASE_SETUP.md with instructions for Supabase project creationStep 7: Split Settings Files
config/settings.pyconfig/settings/__init__.py (empty)config/settings/base.py with core settings (see implementation guide below)config/settings/dev.py with development settingsconfig/settings/prod.py with production settingsStep 8: Create Core App
apps/__init__.py (empty)apps/core/__init__.py (empty)apps/core/apps.py with CoreConfigapps/core/models.py with UUIDModel and Userapps/core/admin.py with UserAdminapps/core/factories.py with UserFactoryapps/core/tests/__init__.py (empty)apps/core/tests/test_models.py with User testsapps/core/migrations/__init__.py (empty)Step 9: Create First App
mkdir -p apps/{first_app_name}
uv run python manage.py startapp {first_app_name} apps/{first_app_name}
Update apps/{first_app_name}/apps.py to use UUID default.
Step 10: Update Config Files
Update config/settings/base.py to include:
Update config/urls.py to include OAuth and API auth URLs
Step 11: Create Initial Migrations
uv run python manage.py makemigrations core
uv run python manage.py makemigrations {first_app_name}
Step 12: Update pyproject.toml
Add tool configurations for mypy, ruff, and pytest at the end of pyproject.toml.
Step 13: Database Setup
If use_supabase == false (Docker):
# Start PostgreSQL container
/usr/bin/make start-docker
# Wait for database to be ready
sleep 3
# Run migrations
uv run python manage.py migrate
If use_supabase == true:
# Display setup instructions
echo ""
echo "=========================================="
echo "⚠️ Supabase Setup Required"
echo "=========================================="
echo ""
echo "Next steps:"
echo "1. Create a Supabase project at https://supabase.com"
echo "2. Go to Settings > Database"
echo "3. Copy the 'Connection string' (URI format)"
echo "4. Add to .env.local:"
echo " DATABASE_URL=postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres"
echo "5. Run: direnv allow"
echo "6. Run migrations: uv run python manage.py migrate"
echo ""
echo "See SUPABASE_SETUP.md for detailed instructions"
echo ""
Step 14: Verify Setup
Run verification checks:
# Check if files exist
[ -f Makefile ] && echo "✅ Makefile"
[ -f .envrc ] && echo "✅ direnv config"
[ -f pytest.ini ] && echo "✅ pytest config"
[ -f CLAUDE.md ] && echo "✅ Documentation"
# Database-specific checks
if [ "$use_supabase" = "true" ]; then
[ -f SUPABASE_SETUP.md ] && echo "✅ Supabase setup instructions"
else
[ -f docker-compose.yml ] && echo "✅ Docker Compose"
fi
# Check Django setup (only if DATABASE_URL is configured for Supabase)
if [ "$use_supabase" = "false" ] || [ -n "$DATABASE_URL" ]; then
uv run python manage.py check
fi
# Check if tests can be collected
uv run pytest --collect-only
Step 15: Display Summary
Show the user:
uv python install 3.12 to automatically download and install Python 3.12uv python install fails: Check network connectivity and suggest manual Python installationCreate docker-compose.yml for local PostgreSQL:
version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: ${PROJECT_NAME:-django}_db
environment:
POSTGRES_DB: ${POSTGRES_DB:-django_dev}
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
ports:
- "${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
volumes:
postgres_data:
Create Makefile for common operations:
.PHONY: start-docker stop-docker restart-docker logs shell migrate makemigrations test runserver createsuperuser lint format typecheck
start-docker:
docker-compose up -d
stop-docker:
docker-compose down
restart-docker:
docker-compose restart
logs:
docker-compose logs -f postgres
shell:
uv run python manage.py shell_plus
migrate:
uv run python manage.py migrate
makemigrations:
uv run python manage.py makemigrations
test:
uv run pytest
runserver:
uv run python manage.py runserver
createsuperuser:
uv run python manage.py createsuperuser
lint:
uv run ruff check .
format:
uv run ruff format .
typecheck:
uv run mypy .
# Ensure Python 3.12+ is available
uv python install 3.12
# Initialize uv project with Python 3.12+
uv init --python 3.12 {project_name}
cd {project_name}
# Verify Python version is pinned
echo "3.12" > .python-version
# Add Django and core dependencies
uv add django psycopg[binary] django-environ
# Create Django project structure
uv run django-admin startproject config .
For Docker PostgreSQL (default):
Create .envrc:
# Load environment from .env files
dotenv_if_exists .env
dotenv_if_exists .env.local
# Docker Database (local development)
export POSTGRES_DB="${POSTGRES_DB:-django_dev}"
export POSTGRES_USER="${POSTGRES_USER:-postgres}"
export POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-postgres}"
export POSTGRES_PORT="${POSTGRES_PORT:-5432}"
export DATABASE_URL="${DATABASE_URL:-postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${POSTGRES_PORT}/${POSTGRES_DB}}"
# Django
export DJANGO_SETTINGS_MODULE="${DJANGO_SETTINGS_MODULE:-config.settings.dev}"
export DJANGO_SECRET_KEY="${DJANGO_SECRET_KEY:-dev-secret-key-change-in-production}"
export DEBUG="${DEBUG:-true}"
# Allow local overrides
source_env_if_exists .envrc.local
Create .env.example:
# Database Configuration
POSTGRES_DB=django_dev
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_PORT=5432
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/django_dev
# Django Configuration
DJANGO_SETTINGS_MODULE=config.settings.dev
DJANGO_SECRET_KEY=dev-secret-key-change-in-production
DJANGO_SUPERUSER_PASSWORD=admin
DEBUG=true
For Supabase (--with-supabase):
Create .envrc:
# Load environment from .env files
dotenv_if_exists .env
dotenv_if_exists .env.local
# Supabase Database
# Set DATABASE_URL in .env.local (see SUPABASE_SETUP.md)
export DATABASE_URL="${DATABASE_URL:-}"
# Django
export DJANGO_SETTINGS_MODULE="${DJANGO_SETTINGS_MODULE:-config.settings.dev}"
export DJANGO_SECRET_KEY="${DJANGO_SECRET_KEY:-dev-secret-key-change-in-production}"
export DEBUG="${DEBUG:-true}"
# Allow local overrides
source_env_if_exists .envrc.local
Create .env.example:
# Supabase Configuration
# Get these values from your Supabase project:
# https://supabase.com/dashboard/project/[PROJECT-REF]/settings/database
DATABASE_URL=postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres
# Django Configuration
DJANGO_SETTINGS_MODULE=config.settings.dev
DJANGO_SECRET_KEY=dev-secret-key-change-in-production
DJANGO_SUPERUSER_PASSWORD=admin
DEBUG=true
Create SUPABASE_SETUP.md:
# Supabase Setup Instructions
This project is configured to use Supabase as the PostgreSQL database.
## Steps
1. **Create a Supabase Project**
- Go to https://supabase.com
- Click "New Project"
- Choose your organization and set a database password
2. **Get Database Connection String**
- Go to Settings > Database
- Find "Connection string" section
- Copy the "URI" format connection string
- It looks like: `postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres`
3. **Configure Local Environment**
- Create `.env.local` file (gitignored):
```bash
DATABASE_URL=postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres
```
- Replace `[PROJECT-REF]`, `[PASSWORD]`, and `[REGION]` with your actual values
- Run `direnv allow` to load the environment
4. **Run Migrations**
```bash
uv run python manage.py migrate
uv run python manage.py createsuperuser
.env.local (it's in .gitignore)
### Step 3: Settings Configuration
Split `config/settings.py` into modular files:
**config/settings/base.py** (core settings):
```python
"""Django settings for {project_name} project."""
import os
from pathlib import Path
import environ
# Build paths
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Environment variables
env = environ.Env()
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
# Security
SECRET_KEY = env('DJANGO_SECRET_KEY')
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third-party apps
'rest_framework',
'oauth2_provider',
'django_htmx',
# Local apps
'apps.core',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django_htmx.middleware.HtmxMiddleware',
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
# Database
DATABASES = {
'default': env.db('DATABASE_URL'),
}
# Custom User model
AUTH_USER_MODEL = 'core.User'
# Password validation
AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]
# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files
STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [BASE_DIR / 'static']
# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.UUIDField'
# REST Framework
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100,
}
# OAuth2
OAUTH2_PROVIDER = {
'SCOPES': {'read': 'Read scope', 'write': 'Write scope'},
'ACCESS_TOKEN_EXPIRE_SECONDS': 36000,
}
config/settings/dev.py (development):
"""Development settings."""
from .base import *
DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '[::1]']
# Development apps
INSTALLED_APPS += [
'django_extensions',
]
# Console email backend
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
config/settings/prod.py (production):
"""Production settings."""
from .base import *
DEBUG = False
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[])
# Security settings
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
# Static files
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
apps/core/models.py (with full type annotations):
"""Core models with UUID base class."""
import uuid
from django.contrib.auth.models import AbstractUser
from django.db import models
class UUIDModel(models.Model):
"""Abstract base class for models with UUID primary keys."""
id: models.UUIDField = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False
)
created_at: models.DateTimeField = models.DateTimeField(auto_now_add=True)
updated_at: models.DateTimeField = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
def __str__(self) -> str:
return str(self.id)
class User(AbstractUser, UUIDModel):
"""Custom user model with UUID primary key."""
email: models.EmailField = models.EmailField(unique=True)
class Meta:
db_table = 'users'
ordering = ['-created_at']
def __str__(self) -> str:
return self.email
apps/core/admin.py (with type annotations):
"""Admin configuration for core models."""
from typing import Any
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.http import HttpRequest
from .models import User
@admin.register(User)
class UserAdmin(BaseUserAdmin):
"""Admin for custom User model."""
list_display: list[str] = ['email', 'username', 'is_staff', 'is_active', 'created_at']
list_filter: list[str] = ['is_staff', 'is_active', 'created_at']
search_fields: list[str] = ['email', 'username']
ordering: list[str] = ['-created_at']
Ask user: "What should be the first app to create?" (e.g., 'accounts', 'blog', 'api')
Then:
mkdir -p apps/{app_name}
uv run python manage.py startapp {app_name} apps/{app_name}
Update apps/{app_name}/apps.py:
from django.apps import AppConfig
class {AppName}Config(AppConfig):
default_auto_field = 'django.db.models.UUIDField'
name = 'apps.{app_name}'
Add HTMX example view in first app:
apps/{app_name}/views.py:
"""Example HTMX views."""
from django.shortcuts import render
def index(request):
"""Index view with HTMX support."""
if request.htmx:
return render(request, 'partials/content.html')
return render(request, 'index.html')
templates/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ project_name }}</title>
<script src="https://unpkg.com/[email protected]"></script>
</head>
<body>
<h1>Welcome to {{ project_name }}</h1>
<div hx-get="/" hx-trigger="load" hx-swap="innerHTML">
Loading...
</div>
</body>
</html>
templates/partials/content.html:
<div>
<p>This content was loaded via HTMX!</p>
</div>
pytest.ini:
[pytest]
DJANGO_SETTINGS_MODULE = config.settings.dev
python_files = tests.py test_*.py *_tests.py
addopts = --reuse-db --cov=apps --cov-report=html --cov-report=term
testpaths = apps
conftest.py (with type annotations):
"""Pytest configuration and fixtures."""
import pytest
from pytest_factoryboy import register
from rest_framework.test import APIClient
from apps.core.factories import UserFactory
from apps.core.models import User
# Register factories
register(UserFactory)
@pytest.fixture
def api_client() -> APIClient:
"""DRF API client."""
return APIClient()
@pytest.fixture
def authenticated_client(api_client: APIClient, user: User) -> APIClient:
"""Authenticated API client."""
api_client.force_authenticate(user=user)
return api_client
apps/core/factories.py (with type annotations):
"""Factory Boy factories for core models."""
from typing import Any
import factory
from factory.django import DjangoModelFactory
from .models import User
class UserFactory(DjangoModelFactory):
"""Factory for User model."""
class Meta:
model = User
email: factory.Faker = factory.Faker('email')
username: factory.Faker = factory.Faker('user_name')
is_active: bool = True
is_staff: bool = False
is_superuser: bool = False
@factory.post_generation
def password(
self,
create: bool,
extracted: str | None,
**kwargs: Any
) -> None:
"""Set user password after generation."""
if not create:
return
password = extracted or 'testpass123'
self.set_password(password)
self.save()
apps/core/tests/test_models.py (with type annotations):
"""Tests for core models."""
from typing import Any
from uuid import UUID
import pytest
from apps.core.models import User
@pytest.mark.django_db
class TestUserModel:
"""Tests for User model."""
def test_user_creation(self, user_factory: Any) -> None:
"""Test creating a user."""
user: User = user_factory()
assert user.id is not None
assert user.email
assert user.username
def test_user_str(self, user_factory: Any) -> None:
"""Test user string representation."""
user: User = user_factory(email="[email protected]")
assert str(user) == "[email protected]"
def test_user_uuid_primary_key(self, user_factory: Any) -> None:
"""Test user has UUID primary key."""
user: User = user_factory()
assert isinstance(user.id, UUID)
Add to pyproject.toml (with strict typing enabled):
[tool.mypy]
plugins = ["mypy_django_plugin.main"]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true # Strict: all functions must have type annotations
warn_redundant_casts = true
warn_unused_ignores = true
strict_equality = true
check_untyped_defs = true
exclude = [
"migrations/",
"venv/",
".venv/",
]
[[tool.mypy.overrides]]
module = [
"factory.*",
"environ.*",
"oauth2_provider.*",
"rest_framework.*",
]
ignore_missing_imports = true
[tool.django-stubs]
django_settings_module = "config.settings.dev"
[tool.ruff]
line-length = 100
target-version = "py312"
exclude = [
"migrations",
".venv",
"venv",
]
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "UP"]
ignore = ["E501"]
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
"*/migrations/*" = ["E501", "N806"]
"*/tests/*" = ["F401", "F811"]
"*/admin.py" = ["F401"]
"*/models.py" = ["F401"]
"*/views.py" = ["F401"]
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "config.settings.dev"
python_files = ["tests.py", "test_*.py", "*_tests.py"]
addopts = "--reuse-db --cov=apps --cov-report=html --cov-report=term"
testpaths = ["apps"]
Note: disallow_untyped_defs = true enforces that all functions and methods must have type annotations. This is intentional to ensure maximum compatibility with AI coding assistants.
config/urls.py:
"""URL configuration."""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')),
path('api-auth/', include('rest_framework.urls')),
]
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
.venv/
venv/
ENV/
env/
# Django
*.log
db.sqlite3
db.sqlite3-journal
/static/
/staticfiles/
/media/
# Environment variables
.env
.envrc.local
# Testing
.pytest_cache/
.coverage
htmlcov/
.tox/
# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Docker
postgres_data/
See template in templates/CLAUDE.md.template.
# Core dependencies
uv add django psycopg[binary] django-environ
# Third-party apps
uv add djangorestframework django-oauth-toolkit django-htmx pydantic
# Development tools
uv add --group dev pytest pytest-django pytest-cov pytest-asyncio
uv add --group dev factory-boy pytest-factoryboy
uv add --group dev mypy django-stubs types-requests
uv add --group dev ruff
uv add --group dev django-extensions ipython
# Create migrations for core app
uv run python manage.py makemigrations core
# Run migrations
uv run python manage.py migrate
# Create superuser
export DJANGO_SUPERUSER_PASSWORD=admin
uv run python manage.py createsuperuser --noinput --username admin --email [email protected]
After setup, verify:
config/ and apps/ layoutdirenv allow succeedsdocker ps shows postgres).env.localuv run python manage.py runserver startsuv run pytest passesuv run mypy . passes with strict mode (disallow_untyped_defs = true)uv run ruff check . passes/oauth/ endpoint accessible/python-experts:django-dev - Django development patterns/python-experts:django-api - API development with DRF/devops-data:direnv - Environment management/git-workflow:commit - Commit the initial projectnpx claudepluginhub jpoutrin/product-forge --plugin python-expertsEnforces opinionated Django patterns: 1-file-per-model organization, UUID primary keys, timestamps, soft deletes, Dynaconf config, uv/pyproject.toml deps, Docker structure for project setup and models.
Bootstraps new Django projects or adds production components (auth, payments, async/WebSockets, Docker, CI/CD, Tailwind+DaisyUI, S3, Sentry) to existing codebases.
Alias that redirects to python-development-python-scaffold for scaffolding production-ready Python applications with uv, FastAPI, Django, and type hints.