How to set up settings, migrations, tests and type checking in a Django project so a coding agent can change models and verify its work, and how the Encore SDK adds Postgres and object storage to the same project.
Django was used by 35 percent of respondents to the 2024 Python Developers Survey, and 12.6 percent of all respondents to the 2025 Stack Overflow Developer Survey worked with it. It gives a coding agent more to work with than most Python frameworks, because the project layout is conventional, models usually live in each app's models.py, and makemigrations writes the migration from a model change.
Agent sessions tend to go wrong in the setup around Django, for example with a DATABASE_URL in a .env that only one developer has, a SQLite database in tests while production runs on Postgres, migrations generated on one branch and forgotten on another, and an ORM that a type checker cannot see into without extra stubs.
Claude Code's guidance for agents is to give them a check they can run, such as tests or a build, and in a Django project that check is a combination of the test suite, manage.py check, makemigrations --check and a type checker, and the setup decides whether the agent can run all of them on its own.
What to weigh when choosing:
.env.Encore combines a conventional Django project, with manage.py, the ORM, admin, auth and sessions, with infrastructure declared in Python through an SDK you add to it, so the Postgres database and object storage buckets the project uses are module-level declarations that Encore provisions locally, in tests, in preview environments and in your own AWS or GCP account. Django keeps owning the schema and its migrations, and the agent no longer needs a .env with a connection string to start working, because encore run starts Postgres locally and hands the connection to the settings module.

The resources live in one module, declared without an Encore migrations directory, because Django manages the schema:
# storage/resources.py
from encore.storage import objects
from encore.storage import postgres
uploads = objects.Bucket("uploads")
# Django manages the schema through its own migrations.
db = postgres.Database("django")
settings.py builds Django's standard PostgreSQL configuration from the connection string Encore supplies, parsed with psycopg so escaping and connection options are kept:
# config/settings.py (excerpt)
from psycopg.conninfo import conninfo_to_dict
from storage.resources import db
connection = conninfo_to_dict(db.connection_string)
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": connection.pop("dbname"),
"USER": connection.pop("user", ""),
"PASSWORD": connection.pop("password", ""),
"HOST": connection.pop("host", ""),
"PORT": connection.pop("port", ""),
"OPTIONS": connection,
}
}
Management commands run through Encore so they receive the same runtime configuration, which gives the agent one way to generate and apply migrations in any environment:
encore run starts the project.Under encore test, pytest runs against an isolated database, and a module fixture applies Django's migrations to it before the tests that need the ORM:
# tests/test_orm.py
import pytest
from django.core.management import call_command
from django.db import connections
from django.test import Client
from config.wsgi import application # Configure Django and load its apps.
from storage.models import Note
@pytest.fixture(scope="module")
def migrated_database():
# Encore supplies the isolated database; Django owns its schema.
call_command("migrate", interactive=False, verbosity=0)
yield
connections.close_all()
def test_create_note(migrated_database):
response = Client().post("/notes/", {"title": "hello"})
assert response.status_code == 201
assert Note.objects.filter(title="hello").exists()
Views can use the bucket through asgiref.sync.async_to_sync, since Encore's storage API is async and classic Django views are synchronous. The local MCP server gives the agent the database schema, traces and a way to query the local database, and a deploy provisions the same database as RDS on AWS or Cloud SQL on GCP, with preview environments for each pull request.
encore run starts Postgres and buckets locally, with no .env to share.encore test supplies an isolated database for the test suite.Encore provisions the database but does not run Django migrations automatically, so committed migrations still need applying, and Django ORM queries are not traced because they go through psycopg rather than the SDK. The example project adds django-stubs and Pyright as dev dependencies, which works the same with or without Encore. Python support is in beta, and you can sign up for access.
The common setup reads the connection from the environment, following the twelve-factor pattern, with django-environ parsing a DATABASE_URL into Django's format:
# config/settings.py (excerpt)
from pathlib import Path
import environ
BASE_DIR = Path(__file__).resolve().parent.parent
env = environ.Env()
environ.Env.read_env(BASE_DIR / ".env")
DATABASES = {"default": env.db("DATABASE_URL")}
The agent needs a working .env and a running Postgres before anything works, so a .env.example and the start command belong in AGENTS.md. It also helps to keep real credentials out of the agent's reach, and Claude Code can deny reads of .env files.
pytest-django runs Django tests with pytest fixtures, while Django itself still creates a separate, blank test database and destroys it after the run:
import pytest
from orders.models import Order
@pytest.mark.django_db
def test_create_order(client):
response = client.post("/orders/", {"email": "ada@example.com"})
assert response.status_code == 201
assert Order.objects.count() == 1
Pair it with checks that fail when an agent forgets a migration or leaves a configuration error:
makemigrations --check exits non-zero when model changes have no migration.client and django_db instead of TestCase classes.makemigrations --check makes a missing migration a failing check.The test database is created on whatever server the settings point at, so a Postgres server still has to be running for the agent and in CI.
SQLite is Django's default and needs no server, which makes it tempting for agent sessions, but it also accepts things Postgres rejects, and Postgres features such as JSONField lookups, array fields and some constraints behave differently or do not exist, so an agent can get a green test run for code that fails on the production database, so it is best kept for prototypes, with tests switched to Postgres before agents start writing migrations.
AGENTS.md.makemigrations --check and manage.py check in CI.For Django next to FastAPI and Flask, see FastAPI vs Django vs Flask, and for a wider comparison, see the best Python backend frameworks.
Keep the database connection out of hand-edited files, commit every generated migration and fail CI with makemigrations --check, run tests against real Postgres in a separate test database, add django-stubs and Pyright so the agent can type check, and document the commands in AGENTS.md or CLAUDE.md. Encore covers the database part by provisioning Postgres for the project locally, in tests and in your own AWS or GCP account, while Django keeps its ORM, admin and migrations.
Add the encore-dev package, declare the database with postgres.Database("django") in a resources module, and build DATABASES in settings.py from db.connection_string using psycopg's conninfo_to_dict. Django keeps owning the schema, so you run makemigrations and migrate through encore exec, and encore test gives the test suite an isolated database. Python support in Encore is in beta.
Not if production runs on Postgres. SQLite accepts queries and constraints that Postgres treats differently, so an agent can get a passing suite for code that fails in production. Run the tests against Postgres instead; Django already creates a separate, blank test database and destroys it after the run.
Deploy to your cloud on AWS and Google Cloud
without managing infrastructure
Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.