django-deprecate-fields
Deprecate Django model fields safely and remove them later without breaking production.
Repository Health
Technical Analysis
django-deprecate-fields provides a deprecate_field() wrapper for Django model fields that formalizes a safe, three-step deletion process: mark the field as deprecated, deploy that change everywhere, then delete the field entirely. Wrapping a field automatically makes it nullable during makemigrations/migrate while replacing runtime access to the field with a descriptor that logs a DeprecationWarning (or optionally raises) whenever code still reads or writes it.
This lets teams find every remaining reference to a field before it is physically removed from the schema, instead of discovering broken code paths after the column is already gone. It has no dependencies beyond Django itself and integrates purely through the model’s field declarations.
What You Get
- A
deprecate_field()wrapper that marks a Django model field as deprecated in place - Automatic
null=Truebehavior duringmakemigrations/migrate/showmigrationsso the schema stays migratable - A descriptor that logs a
DeprecationWarningon read/write access outside migration commands - An optional
raise_on_accessmode that raisesFieldDeprecatedErrorinstead of warning - A
return_insteadoption to substitute a fixed value or callable for the deprecated field’s value
Common Use Cases
- Safely retiring a Django model field across a multi-service deployment without a hard cutover
- Surfacing every remaining read/write of a field via logged deprecation warnings before deleting it
- Enforcing a hard failure (
raise_on_access) in staging to catch lingering references before production - Migrating a column to nullable ahead of a later
makemigrationsthat drops it entirely
Under The Hood
Architecture The package is a single module, deprecate_field.py, exporting one function (deprecate_field) and one descriptor class (DeprecatedField). deprecate_field() inspects sys.argv to detect whether the current process is a migration command (makemigrations, migrate, showmigrations, or names added via DEPRECATE_FIELD_CUSTOM_MIGRATION_COMMAND); if so it returns the original field with null=True forced so migrations succeed, otherwise it wraps the field in a DeprecatedField descriptor that intercepts __get__/__set__ on the model class.
Tech Stack Pure Python with a single runtime dependency, Django>=2.1. No build step, no compiled extensions, no third-party dependencies beyond Django’s own settings and logging.
Code Quality tests/test_deprecate_field.py exercises the wrapper against a real Django test project (tests/test_project/settings.py) via Django’s own manage.py test runner, and tox.ini runs the suite across a matrix of Python/Django version combinations. The implementation is small enough (roughly 90 lines) that its behavior is easy to audit directly.
API Design The public surface is a single function call wrapped around an existing field declaration (field1 = deprecate_field(models.CharField())), which keeps the migration path to adoption trivial — no schema changes to app code are needed beyond that one line, and the return_instead/raise_on_access parameters cover the two most common deprecation policies (silent warning with a fallback value vs. hard failure) without extra configuration.