Using Claude Code with Django: Optimization Tips and Context Management

Using Claude Code with Django: Optimization Tips and Context Management
Django projects have a specific structure that AI coding agents consistently mishandle. The framework's "batteries included" philosophy means a single feature spans models, views, URL configurations, templates, serializers, middleware, admin customizations, management commands, and migrations. Ask Claude Code to add a field to a user profile, and it needs to touch at least four files — and know the exact patterns your project uses for each one.
Most AI coding failures on Django aren't about model intelligence. They're about the agent not seeing the full picture of how Django connects its pieces. Fix the context, and the code quality jumps dramatically.
Django's Context Challenges
Django's architecture creates context requirements that differ fundamentally from frontend frameworks or microservice backends.
The MTV Pattern Sprawl
Django follows Model-Template-View (MTV), but a real Django project's dependency graph is wider than three layers. A single feature typically involves:
- Model (`models.py`) — The database schema, field types, relationships, validators, and custom managers
- View (`views.py` or `viewsets.py`) — The business logic, authentication, permissions, and response formatting
- URL configuration (`urls.py`) — The routing rules, path converters, and namespace definitions
- Serializer (`serializers.py`) — The API data transformation layer (DRF projects)
- Template (`templates/`) — The HTML rendering with template tags and filters
- Form (`forms.py`) — The validation and input handling layer
- Admin (`admin.py`) — The admin interface customization
- Migration (`migrations/`) — The database schema evolution
- Test (`tests.py` or `tests/`) — The test suite covering all of the above
Modifying any one of these files often requires understanding two or three others. Change a model field? The serializer, form, and migration all need updates. Add a URL pattern? The view must match its signature. The interconnections are extensive and follow Django-specific conventions that the agent must know.
ORM Complexity
Django's ORM is expressive but convention-heavy. Field types map to specific database column types. `ForeignKey` requires `on_delete` behavior. `ManyToManyField` creates intermediate tables. Custom managers add querysets. Model methods can be properties, classmethods, or regular methods with different implications.
Claude Code frequently makes ORM mistakes when it lacks model context:
- Wrong field types — Using `CharField` where `TextField` is appropriate, or `IntegerField` where `PositiveIntegerField` would enforce constraints
- Missing `on_delete` — Forgetting `on_delete=models.CASCADE` on `ForeignKey` fields (a required parameter that's easy to miss)
- Incorrect related names — Using default `related_name` patterns that conflict with existing reverse relations
- N+1 query patterns — Writing view code that triggers N+1 queries because the agent doesn't see the queryset optimization (`select_related`, `prefetch_related`) context
URL Routing Conventions
Django URL routing uses `urlpatterns` lists with `path()` or `re_path()` functions. URL configurations can be included from app-level `urls.py` files into the project-level `urls.py`. Namespaces, app names, and URL naming conventions vary between projects.
Without seeing both the project-level and app-level URL configurations, the agent generates URLs that don't match the existing naming pattern, creates duplicate path names, or misses the namespace prefix required for reverse URL lookups.
Middleware and Signal Chains
Django middleware processes every request and response in a defined order. Signals fire on model save, delete, and other events. Both create implicit dependencies that aren't visible from looking at a single view or model file.
An agent that doesn't see the middleware stack might duplicate authentication logic that middleware already handles. An agent that doesn't see signal handlers might add logic to a model's `save()` method that duplicates what a `post_save` signal already does.
Common AI Mistakes with Django
These are the Django-specific errors that appear most frequently in Claude Code sessions:
1. Wrong model field types. The agent uses `models.CharField(max_length=255)` for a text field that should be `models.TextField()`, or uses `models.FloatField()` for currency (should be `models.DecimalField(max_digits=10, decimal_places=2)`). These compile fine but create data integrity issues.
2. Missing migrations. The agent modifies models but doesn't generate migration files, or generates migrations manually instead of using `makemigrations`. Hand-written migrations often miss dependency chains and fail when applied.
3. Incorrect URL patterns. The agent creates URL patterns with incorrect path converters (`<int:pk>` vs `<str:slug>`), mismatches between URL parameter names and view function parameter names, or naming conflicts with existing URL patterns in the project.
4. Template context mismatches. The agent passes variables to templates with different names than the template expects, or references template tags/filters without loading the correct template tag library with `{% load %}`.
5. Serializer/model drift. In DRF projects, the agent modifies the model without updating the serializer, or adds serializer fields that reference model fields that don't exist. This causes runtime `AttributeError` exceptions.
6. Ignoring project conventions. Every Django project develops conventions: class-based views vs function-based views, DRF viewsets vs APIViews, factory_boy vs fixtures for tests. The agent defaults to whatever pattern is most common in its training data, which may not match your project.
Setting Up Claude Code for Django
The CLAUDE.md Approach
A well-crafted CLAUDE.md file for a Django project should document:
```
Project Structure
- Python 3.12, Django 5.1, DRF 3.15
- Apps: users, products, orders, payments, notifications
- Database: PostgreSQL 16
- Task queue: Celery with Redis broker
Conventions
- Views: Class-based views (APIView for DRF, TemplateView/FormView for templates)
- URLs: namespaced per app, named with app_name:action-model pattern
- Models: TimeStampedModel base class for all models (adds created_at, updated_at)
- Tests: pytest-django with factory_boy, fixtures in tests/fixtures/
- Serializers: ModelSerializer with explicit fields (never fields = '__all__')
Key Patterns
- Authentication: custom User model in users app, JWT via djangorestframework-simplejwt
- Permissions: custom permission classes in core/permissions.py
- Pagination: CursorPagination for list endpoints
- Error handling: custom exception handler in core/exceptions.py
```
This document gives Claude Code the conventions it needs without requiring it to explore your entire project. The agent knows to use `APIView` instead of `@api_view`, to inherit from `TimeStampedModel`, and to write serializers with explicit field lists.
Model Relationships Documentation
For projects with complex model relationships, include an entity-relationship summary:
```
Model Relationships
- User -> Profile (one-to-one)
- User -> Order (one-to-many)
- Order -> OrderItem (one-to-many)
- OrderItem -> Product (many-to-one)
- Product -> Category (many-to-one, nullable)
- Product <-> Tag (many-to-many)
```
This gives the agent the relationship context it needs to write correct querysets, serializers, and joins without reading every model file.
Optimizing Context for Django Tasks
Different Django tasks require different context slices. Here's the minimum context for common task types:
Feature Implementation (Model + View + URL + Serializer)
When building a new feature — say, a product review system — provide:
- The model file where the new model will live
- The views file for the app
- The app-level `urls.py`
- The serializers file (for DRF projects)
- Related models (e.g., `Product` and `User` if reviews link to both)
- Base classes (`TimeStampedModel`, base `APIView`, base `ModelSerializer`)
This set — typically 6-8 files — gives the agent everything it needs to implement a feature that integrates with your existing patterns.
Bug Fixing (Model + View + URL + Error Context)
For bug fixes, include:
- The file where the bug manifests
- The model it operates on
- The URL pattern that routes to it
- The traceback or error message verbatim
- Related middleware or signal handlers if the bug involves request processing
API Development (Model + Serializer + View + URL)
For DRF API work, the critical quartet is model + serializer + viewset + URL router. Include all four for every API task. Missing the serializer is the most common context gap — the agent modifies the model or view but doesn't know what the serializer currently exposes.
Database Work (Model + Existing Migrations)
When modifying models, include the most recent migration file for context. The agent needs to see the current state of the database schema as Django's migration system understands it, not just the model code. This prevents migration conflicts and ensures proper dependency chains.
Testing Workflows with Django
Django testing with Claude Code benefits from explicit test context. The agent writes significantly better tests when it can see:
- Your test base class — If you have a `BaseTestCase` with setup methods, include it
- Existing test patterns — Include 2-3 existing tests from the same app as examples
- Factory definitions — If using factory_boy, include the relevant factories
- Fixture files — If using JSON/YAML fixtures, include or reference them
- conftest.py — Pytest fixtures and shared configuration
pytest-django Best Practices
When using pytest-django, include your `conftest.py` in context. It likely contains fixtures that the agent should reuse rather than recreate:
```python
Don't let the agent write this:
@pytest.fixture
def api_client():
return APIClient()
When your conftest.py already has:
@pytest.fixture
def authenticated_client(user):
client = APIClient()
client.force_authenticate(user=user)
return client
```
Without the conftest, the agent creates redundant fixtures. With it, the agent reuses existing setup and writes tests that match your project's patterns.
factory_boy Integration
Include factory definitions when asking for test generation. The agent needs to know your `UserFactory`, `ProductFactory`, and `OrderFactory` to generate test data correctly. Without factories in context, it falls back to `Model.objects.create()` calls with hardcoded data — which works but doesn't match factory-based projects.
How vexp Handles Python Dependency Graphs
vexp's indexer parses Python source files using AST analysis, extracting:
- Import relationships — `from myapp.models import User` creates an edge from the current file to `myapp/models.py`, specifically to the `User` symbol
- Class hierarchy — `class OrderSerializer(ModelSerializer)` creates an inheritance edge
- Function calls — `User.objects.filter(active=True)` creates a usage edge from the current function to `User` and its manager
- Decorator dependencies — `@login_required`, `@permission_classes([IsAdmin])` create edges to the decorator definitions
- Django-specific patterns — Foreign key references (`ForeignKey('users.User')`) are tracked as cross-model dependencies
When you run a task like "add a discount field to the Order model," vexp's `run_pipeline` traverses the graph from `Order` outward, collecting:
- The model file containing `Order`
- All serializers that reference `Order`
- All views that query or create `Order` instances
- URL patterns that route to those views
- Test files that test `Order` functionality
- The most recent migration file for the app
This traversal typically returns 10-15 files — the complete blast radius of a model change — without manual specification. The agent sees every file it needs to update, reducing the chance of partial changes that break at runtime.
Benchmark Data from FastAPI Projects
vexp's Python indexing benchmarks, measured primarily on FastAPI projects, are directly applicable to Django:
- Token reduction: 65-70% compared to manual file exploration — the agent receives the dependency neighborhood instead of reading entire apps
- Error reduction: 45% fewer runtime errors in generated code — because the agent sees all related files, not just the one being edited
- Turn reduction: 50% fewer conversation turns per task — the agent has enough context to get it right on the first attempt
These numbers translate directly to Django projects because the underlying challenge is the same: Python dependency tracking across models, views, serializers, and tests. The ORM layer adds Django-specific edges, but the graph traversal mechanism is identical.
On a 300-file Django project with 12 apps, vexp indexes in under 30 seconds and serves context capsules in under 200ms. The index updates incrementally as files change, so there's no re-indexing overhead during development.
Practical Django Development Workflow
Daily Workflow with Claude Code
1. Start the context engine. If using vexp, it runs as a background daemon. If not, prepare your CLAUDE.md with project structure and conventions.
2. Scope tasks to one app. Django's app structure is a natural task boundary. "Add review functionality to the products app" is a well-scoped task. "Refactor the entire project to use DRF viewsets" is too broad — break it into per-app migrations.
3. Model-first development. Have Claude Code write the model changes first. Review the field types, relationships, and constraints before proceeding. Then generate the migration with `python manage.py makemigrations`. Then implement the view/serializer/URL changes.
4. Include the test context. When implementing features, include the app's existing test file and your conftest. Ask the agent to write tests alongside the implementation. Django test failures catch model/view/URL mismatches before they reach production.
5. Use `manage.py` commands for verification. After model changes: `python manage.py check` catches common issues. After migration generation: `python manage.py showmigrations` confirms the migration graph is valid. After all changes: `python manage.py test app_name` runs the app's test suite.
Multi-App Feature Work
Features that span multiple Django apps — like an order system that touches `users`, `products`, `orders`, and `payments` — require careful context scoping.
Approach 1: Model layer first, then views. Implement all model changes across apps, generate migrations, then implement views. This ensures the data layer is consistent before business logic is added.
Approach 2: One app at a time. Complete the feature in `orders` (model + view + URL + serializer + tests), then extend to `payments`, then `notifications`. Each step is self-contained and testable.
Both approaches work with Claude Code. The key is never asking the agent to implement across all apps simultaneously — the context requirements exceed what can be provided effectively, and the agent makes more mistakes when juggling multiple app conventions at once.
Migration Safety
Django migrations are the most dangerous area for AI-generated code. A bad migration can destroy production data. Safeguards:
- Never let the agent write migrations manually. Always use `makemigrations`.
- Review migration files before applying. Check for `RunPython` operations, data migrations, and irreversible operations.
- Include the latest migration in context so the agent knows the current schema state.
- Test migrations with `python manage.py migrate --plan` to verify the execution order.
AI-generated model changes are usually fine. AI-generated migration files are risky. Let Django's migration framework handle the translation from model changes to migration operations.
The Django Development Loop
Effective Claude Code usage with Django follows a predictable loop: scope to one app, provide model + view + URL + serializer context, implement model-first, generate migrations with `makemigrations`, implement views and serializers, write tests, verify with `manage.py check` and the test suite.
Each step is narrow enough for the agent to handle well, and the verification steps catch errors before they propagate. With a dependency graph providing the right context automatically, this loop runs with minimal manual file selection — the agent sees what it needs to see, and doesn't hallucinate Django patterns that don't match your project.
Frequently Asked Questions
Why does Claude Code struggle with Django projects?
What context should I provide Claude Code for Django feature development?
How do I prevent Claude Code from generating bad Django migrations?
Does vexp work with Django and Python projects?
What's the best workflow for multi-app Django features with Claude Code?
Nicola
Developer and creator of vexp — a context engine for AI coding agents. I build tools that make AI coding assistants faster, cheaper, and actually useful on real codebases.
Related Articles

Vibe Coding Is Fun Until the Bill Arrives: Token Optimization Guide
Vibe coding with AI is addictive but expensive. Freestyle prompting without context management burns tokens 3-5x faster than structured workflows.

Windsurf Credits Running Out? How to Use Fewer Tokens Per Task
Windsurf credits deplete fast because the AI processes too much irrelevant context. Reduce what it needs to read and your credits last 2-3x longer.

Best AI Coding Tool for Startups: Balancing Cost, Speed, and Quality
Startups need speed and budget control. The ideal AI coding stack combines a free/cheap agent with context optimization — here's how to set it up.