CodeVetter · Repo Unpack · Contributor handoff
django/django
Edit the django/ package as a library with a stable import surface, and prove changes with a narrow runtests.py label. Read the handler, settings, and the subsystem you touch before writing code. Black, isort, and flake8 are enforced. Deprecation warnings are test failures. Do not treat this checkout as an application: there is no project settings module until startproject creates one. Avoid full-suite runs, native GIS, and alternate databases unless the task needs them.
- Read first: django/__init__.py (version and setup), django/conf/__init__.py plus global_settings.py, django/core/handlers/base.py, django/core/management/__init__.py, and the subsystem file (ORM query.py/base.py, urls/resolvers.py, or the contrib app). Design intent is loose coupling: templates do not know about requests, the database layer does not know about display.
- Safe test command, from a venv with pip install -e . and tests/requirements/py3.txt: cd tests && ./runtests.py <label> -v2. Labels are package names such as handlers, csrf_tests, or auth_tests. tox -e py3 -- <label> is the same runner. Do not start with the full suite.
- Formatting: black target py312 (force-excludes tests/test_runner_apps/tagged/tests_syntax_error.py) and isort profile black, known_first_party django, checked on django, tests, and scripts. flake8 is the lint gate in CI.
- runtests.py makes RemovedInNextVersionWarning, RemovedAfterNextVersionWarning, ResourceWarning, and RuntimeWarning errors. Code that emits those warnings fails CI even if assertions pass. EMAIL_* and get_connection() already warn with RemovedInDjango2028Warning.
- Settings trap: any import-time access to django.conf.settings before DJANGO_SETTINGS_MODULE or settings.configure() raises ImproperlyConfigured. Model import before apps.populate raises AppRegistryNotReady. Tests rely on runtests.py to configure settings; ad-hoc scripts must do it themselves.
- call_command() sets skip_checks=True by default, so it will not reproduce a failing system check that run_from_argv would run. ManagementUtility fetches commands only after setup, except the runserver autoreload bootstrap.
- get_commands is functools.cache. Adding a command module or changing INSTALLED_APPS in-process requires clearing that cache or the new command stays invisible. Command instances live in app packages as class Command(BaseCommand).
- Project and app scaffolds are .py-tpl files under django/conf/project_template and django/conf/app_template, not .py modules. Editing a generated-looking settings.py that is not in the tree will not change startproject.
- Do not hand-edit compiled .mo catalogs under django/conf/locale or contrib/*/locale. Translation source is the .po files; makemessages and compilemessages are the commands. isort/black CI does not cover those catalogs the way it covers Python. (inferred)
- Async trap: a coroutine view cannot be combined with ATOMIC_REQUESTS. Admin trap: composite primary keys and abstract models cannot be registered. Migration trap: a plan that both applies and unapplies in one executor.migrate call raises InvalidMigrationPlan.
- Security-sensitive edits belong with the matching tests: csrf_tests for CsrfViewMiddleware, auth_tests for hashers and backends, check_framework or security checks for W009. Deployment checks do not run unless include_deployment_checks is requested, so a unit test must opt in.
- GIS and non-SQLite backends are optional. Changing django/contrib/gis or django/db/backends/postgresql|mysql|oracle is not validated by the default GitHub Actions SQLite job. tox only adds those drivers when the env factor is selected, and you must pass --settings.
- JavaScript for admin is not covered by runtests.py. Changes under django/contrib/admin/static or js_tests need npm test (Node is pinned to 24.15.0 in CI because of a puppeteer break on 24.16). Biome is available as npm run biome.
- Public entrypoints to preserve: execute_from_command_line, get_wsgi_application, get_asgi_application, django.setup, path/re_path/include, Model.save, and QuerySet.filter. Handler classes are documented as private so they can move. Version is read dynamically from django.__version__ for the package metadata.