Opened 44 minutes ago
Last modified 41 minutes ago
#37494 new Cleanup/optimization
Document that RunPython callables receive a StateApps instance
| Reported by: | Thibaut Decombe | Owned by: | |
|---|---|---|---|
| Component: | Documentation | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
The `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, 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.