﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
37494	Document that RunPython callables receive a StateApps instance	Thibaut Decombe		"The [https://docs.djangoproject.com/en/dev/ref/migration-operations/#django.db.migrations.operations.RunPython `RunPython` docs] say the first argument passed to code / reverse_code is ""an instance of django.apps.registry.Apps containing historical models"". 
At runtime it is a `django.db.migrations.state.StateApps` (see `django/db/migrations/operations/special.py`, [https://github.com/django/django/blob/d4b02a7bf937b865e2ffc1584e36f1e753c689b9/django/db/migrations/operations/special.py#L194-L199 RunPython.database_forwards()].

This difference matters to users who follow the docs literally, especially when annotating migration functions:


{{{
def forwards(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None:
    Person = apps.get_model(""myapp"", ""Person"")
}}}


Apps is also the type of the global registry (`django.apps.apps`), whose `get_model()` returns the current models from models.py. 

With the documented annotation, tools such as the django-stubs mypy plugin can't tell this historical registry apart from the global one. They resolve `get_model()` to the current model class, which may have different fields than the historical model (https://github.com/typeddjango/django-stubs/issues/3584).

Proposal: mention `django.db.migrations.state.StateApps` (as a subclass of Apps) in the RunPython docs."	Cleanup/optimization	new	Documentation	dev	Normal				Unreviewed	1	0	0	0	0	0
