These 14 Django prompts help ChatGPT, Claude, Claude Code and Codex with the parts of Django where generic answers go wrong: model design, N+1 queries, data migrations, fat views, forms, template partials, background tasks, async views, tests, production settings and upgrades. Each prompt is a template with blanks you fill in.
Plain Python work, such as type hints or profiling, is in the Python prompts, and raw SQL tuning is in the SQL prompts. For a project instructions file that sets Django rules once, see CLAUDE.md for Django.
How to use these prompts
Copy a prompt, replace each blank in double braces, or keep the default after the colon. {{django_version:6.1}} means Django 6.1 unless you change it.
State your versions. As of October 2026, the Django download page lists 6.1 as the latest release and 5.2 as the LTS. Features differ a lot between them: template partials and the tasks framework arrived in 6.0, and model field fetch modes arrived in 6.1. Django 6.0 and later need Python 3.12 or newer.
Paste models with the code that uses them. A view alone hides the relations that cause extra queries. Include settings only when they matter, and never paste a real SECRET_KEY or database password.
In an agent, name the app and let it run python manage.py test, makemigrations --check and check --deploy. Real command output beats a model's guess.
How do you write Django models and queries?
1. Design models from a spec
Get constraints and indexes right before the first migration, when changes are cheap.
Design Django {{django_version:6.1}} models for this feature:
{{spec}}
Include field types, null and blank choices with a reason for each,
on_delete behavior for every ForeignKey, Meta.constraints
(UniqueConstraint, CheckConstraint) for rules the database should
enforce, and Meta.indexes for the filters and orderings in the spec.
Add __str__ and a sensible default ordering only if pages need it. Show
models.py, then list the queries you expect and which index serves each.
2. Find and fix N+1 queries
The database access optimization guide says to profile first, then use select_related() and prefetch_related(). Django 6.1 adds QuerySet.fetch_mode(), where FETCH_PEERS loads a missing related field for every instance in the queryset at once.
This view runs {{count:120}} queries to render one page.
Models:
{{models}}
View and template:
{{view_and_template}}
Queries from django-debug-toolbar:
{{queries}}
Find each N+1 pattern and fix it with select_related (forward
ForeignKey and one-to-one), prefetch_related or Prefetch objects
(reverse and many-to-many), or annotate for counts. If we're on Django
6.1, say where fetch_mode(models.FETCH_PEERS) or FETCH_RAISE would help.
Add a test using assertNumQueries for the new query count.
3. Move Python loops into the database
The same guide recommends filtering, F() expressions and annotate() in the database, plus bulk methods. It also notes that QuerySet.update() and delete() don't call each instance's save() or delete().
This code loops over rows in Python and is slow on {{rows:500,000}} rows:
{{code}}
Rewrite it so the database does the work: filter and exclude instead of
if-statements, F() for field-to-field math, annotate and aggregate for
totals, update() or bulk_update() for writes, bulk_create() for inserts,
and values_list or iterator() where model instances aren't needed. For
each change, say whether it skips save(), signals or model validation
that the old code relied on.
How do you write safe Django migrations?
4. Write a data migration
The migrations guide says to use historical models through apps.get_model(), because directly imported models "will fail in the future when you try to rerun old migrations." Without a reverse function, migrating backwards raises an exception.
Write a Django data migration for app {{app:billing}} that
{{change:splits the full_name field into first_name and last_name}}.
Models before and after:
{{models}}
Requirements: create it with makemigrations --empty, use
apps.get_model() instead of importing models, pass a reverse function
to RunPython, process rows in batches with iterator() and bulk_update()
for a table of {{rows:2 million}} rows, and keep schema and data changes
in separate migrations. Explain how to test it forward and backward on a
copy of production data.
5. Review a migration before it runs in production
The guide notes that PostgreSQL and SQLite run migrations inside a transaction, while MySQL and Oracle don't, so a failed MySQL migration has to be unpicked by hand.
Review this migration before we deploy it to {{database:PostgreSQL}}
with a {{size:40 million}} row table:
{{migration}}
Output of python manage.py sqlmigrate for it:
{{sql}}
For each operation, say what lock it takes and roughly how long it could
block reads or writes. Flag adding a NOT NULL column without a default,
adding an index without a concurrent option, renames that break running
code during a rolling deploy, and RunPython without a reverse function.
Suggest a safer sequence of migrations if needed.
6. Squash old migrations
Use this when an app has hundreds of migrations and new environments take minutes to set up.
App {{app:orders}} has {{count:240}} migrations. Plan how to squash them
with python manage.py squashmigrations.
Here is the list of migrations and any with RunPython or RunSQL:
{{migrations}}
Tell me: which range to squash, how to handle RunPython functions that
can't be optimized away, how to break a CircularDependencyError if it
appears, and when it is safe to delete the replaced migrations and
remove the replaces attribute. Give a checklist for confirming every
environment has applied the originals first.
How do you build views, forms and templates?
7. Slim down a fat view
For the 200-line view that validates, queries, sends email and renders.
This Django view does too much:
{{view}}
Refactor it: move validation into a Form or ModelForm, move business
logic into plain functions in a services module, keep the view to
reading the request, calling those functions and returning a response.
Decide whether a function-based or class-based view is clearer here and
say why. Keep URLs, templates and behavior the same, and add tests for
the extracted functions.
8. Write a form with real validation
Push rules into the form so every entry point gets the same checks.
Write a Django {{form_type:ModelForm}} for {{purpose:booking a room}}.
Model and rules:
{{model_and_rules}}
Put single-field rules in clean_<field> methods and cross-field rules in
clean(). Use clear error messages a user can act on, attached to the
right field. Prevent mass assignment by listing fields explicitly. Show
the form, the view that uses it, and tests for each validation rule,
including one that submits a field the form should ignore.
9. Render partial updates with template partials
The template language docs say partials, new in Django 6.0, can be rendered on their own with the template.html#partial_name syntax, which suits requests that update one part of a page.
On this page, {{interaction:filtering the table}} reloads the whole page.
Here is the template and view:
{{template_and_view}}
Refactor it with Django 6.0 template partials: wrap the part that
changes in {% partialdef %} with the inline argument, add a view (or a
branch in the existing one) that renders "page.html#partial_name" for
{{client:htmx}} requests, and keep the full page working without
JavaScript. Show both templates and the view, and a test for each
response.
How do you handle background and async work?
10. Move slow work into a background task
The tasks framework docs say Django does not provide a worker, that the built-in backends are for development and testing only, and that task arguments must be JSON-serializable.
This view sends {{work:a PDF invoice by email}} during the request and
takes several seconds:
{{view}}
Move the work into a task with the django.tasks @task decorator and
.enqueue(). Pass IDs, not model instances or datetimes, since arguments
must survive JSON. Enqueue inside transaction.on_commit so the task
never runs before the data exists. Recommend a backend and worker for
{{hosting:a single VPS}} and say what to configure in TASKS. Show how
to test it with the built-in backends.
11. Write an async view safely
The async support docs say you need ASGI to get the benefits, that QuerySet methods have a-prefixed async versions, and that transactions do not yet work in async mode.
Convert this view to async so it can call {{services:three external APIs}}
in parallel:
{{view}}
Use async ORM methods (aget, acreate, async for) where they exist. Wrap
any code that needs a transaction or a sync-only library in a single
sync function called with sync_to_async. Run the API calls concurrently
with timeouts. Tell me what changes in deployment (ASGI server) and how
to spot a SynchronousOnlyOperation error if something is missed.
How do you test and ship a Django app?
12. Write fast, readable tests
The testing tools docs describe setUpTestData() for data created once per test class, force_login() to skip the login flow, and assertNumQueries().
Write tests for this Django feature with {{runner:django.test.TestCase}}:
{{code}}
Create shared data in setUpTestData, log in with force_login, and use
the test Client for full request and response checks. Cover the happy
path, a permission failure (another user's object returns 404 or 403),
invalid form input, and the query count with assertNumQueries. Don't
mock the ORM. Keep each test focused on one behavior and name it after
that behavior.
13. Review production settings
The deployment checklist says "You must never enable debug in production" and recommends running manage.py check --deploy against production settings.
Review these Django production settings:
{{settings}}
Output of python manage.py check --deploy:
{{check_output}}
Check DEBUG, SECRET_KEY loading from the environment, ALLOWED_HOSTS,
CSRF_COOKIE_SECURE, SESSION_COOKIE_SECURE, HTTPS redirect and HSTS,
STATIC_ROOT, LOGGING and CONN_MAX_AGE. On Django 6.0 or later, propose a
SECURE_CSP policy using ContentSecurityPolicyMiddleware, starting in
report-only mode. Rank issues by risk and show the corrected settings.
14. Plan a Django upgrade
The upgrade guide recommends going one feature release at a time and fixing deprecation warnings first with python -Wa manage.py test.
Plan an upgrade from Django {{from:5.2}} to {{to:6.1}}.
requirements.txt and the output of python -Wa manage.py test:
{{files}}
List the steps one feature release at a time. For each step, give the
breaking changes from the release notes that affect code like ours (for
example DEFAULT_AUTO_FIELD now defaulting to BigAutoField in 6.0),
third-party packages that need new versions, and deprecation warnings
to fix first. Note that 6.1 adopted calendar versioning: the release
once planned as 7.0 is now 2028, and RemovedInDjango70Warning became
RemovedInDjango2028Warning. Mark anything you're unsure applies.
Turn your favorite one into a skill
If you run the N+1 or migration review prompt on every pull request, make it a skill so Claude Code or Codex applies it whenever the task matches. Paste the prompt into the free SKILL.md generator to get a valid SKILL.md in your browser. For broader checks before a release, the security review prompts cover auth, injection and secrets in any stack.
To keep these prompts at hand, save them in Kipt. Your prompts live as Markdown in a private GitHub repo you own, blanks like {{django_version:6.1}} stay fillable, and Cmd+K search finds any prompt by name or tag.