Changelog

1.31.1 (2026-06-26)

  • Remove the settings_logging_admin_email_handler fixer because it made an incorrect change and cannot be salvaged.

    Thanks to Mike Edmunds for spotting the mistake in this GitHub comment. PR #671.

1.31.0 (2026-06-25)

  • Support Django 6.1 as a target version.

    PR #646.

  • Add Django 6.1+ mail_get_connection fixer to replace no-argument mail get_connection() calls with mailers.default, and remove inline connection=get_connection() kwargs from mail sending functions.

    PR #666.

  • Add Django 6.1+ mail_fail_silently fixer to remove fail_silently=False keyword arguments from mail sending function calls.

    PR #668.

  • Add Django 6.1+ settings_logging_admin_email_handler fixer to rename the email_backend argument of AdminEmailHandler in the LOGGING setting to using.

    PR #662.

  • Add Django 6.1+ compatibility_imports fixer entries to move BitAnd, BitOr, and BitXor imports from django.contrib.postgres.aggregates to django.db.models.

    PR #658.

  • Add Django 6.1+ transaction_savepoint fixer to rename django.db.transaction’s savepoint to savepoint_create.

    PR #660.

  • Add Django 2.0+ render_to_response fixer to rewrite render_to_response() calls to render(), inserting request as the first argument.

    PR #669.

  • Extend test_http_headers fixer to cover AsyncClient, AsyncRequestFactory, and self.async_client.*() calls.

    Thanks to Benjamin Aduo in PR #633.

  • Extend django_urls fixer to convert translated URL patterns wrapped in translation functions, like _(r'^about/$'), when the pattern is convertible.

    PR #667.

  • Extend django.utils.timezone.utc deprecations fixer to work when no import datetime statement exists, by inserting import datetime as dt when the name dt is unused.

    Thanks to Ryan Siemens for the report in Issue #568 and Benjamin Aduo for the implementation in PR #631.

  • Extend versioned_test_skip_decorators fixer to also remove the entire decorated function or class when the skip condition is always true. For example, when targeting Django 5.2+, a function decorated with @pytest.mark.skipif(django.VERSION >= (5, 2), ...) will be removed.

    PR #648.

  • Extend versioned_test_skip_decorators fixer to support async function definitions.

    PR #649.

  • Add Django 1.11+ fixer permalink to rewrite @models.permalink decorator usages to use reverse() directly.

    PR #647. Thanks to Joerg Sonnenberger for the report in Issue #645 and review.

  • Fix null_boolean_field fixer when NullBooleanField is used in non-call contexts, for example as a base class.

    PR #664.

  • Fix versioned_branches fixer to avoid leaving code with broken syntax emptying a parent block. A pass is now inserted to keep the code valid.

    PR #665.

  • Fix these fixers to correctly handle calls with starred arguments:

    For example, the signal_providing_args fixer now rewrites Signal(providing_args=[...], *args) to Signal(*args).

    PR #670.

1.30.0 (2026-02-24)

  • Support parsing Django versions without a minor part from pyproject.toml. For example, django>=6 will be parsed as for Django 6.0+.

    PR #625.

  • Drop Python 3.9 support.

1.29.1 (2025-10-23)

  • Remove the AppConfig rewriting behaviour of default_auto_field. It was unsafe for projects setting DEFAULT_AUTO_FIELD to a field other than BigAutoField, triggering regressive migrations for primary keys in affected apps.

    PR #606.

1.29.0 (2025-10-06)

  • Add Django 6.0+ fixer mail_api_kwargs to rewrite positional arguments to keyword arguments for some django.core.mail APIs.

    PR #600.

  • Add Django 6.0+ fixer default_auto_field to remove now-redundant auto field specifications. The fixer removes the DEFAULT_AUTO_FIELD setting and AppConfig.default_auto_field attribute when they are set to the new default of django.db.models.BigAutoField.

    Thanks to q0w in PR #591.

  • Add Django 6.0+ fixer stringagg to rewrite StringAgg imports from django.contrib.postgres.aggregates to django.db.models. This fixer replaces the compatibility import rewrite added in 1.27.0, and now correctly wraps the delimiter argument in Value() when it is a string literal.

    PR #596.

  • Add Django 6.0+ fixer settings_admins_managers to rewrite the ADMINS and MANAGERS settings to drop the previously-unused name parts of the tuples.

    PR #601.

1.28.0 (2025-09-09)

  • Support Python 3.14.

1.27.0 (2025-08-27)

  • Support Django 6.0 as a target version.

  • Add Django 6.0+ fixer settings_forms_urlfield_assume_https to remove the transitional setting FORMS_URLFIELD_ASSUME_HTTPS.

    PR #585.

  • Add Django 6.0+ compatibility import rewrite of StringAgg from django.contrib.postgres.aggregates to django.db.models.

    PR #586.

  • Improve the django_urls fixer slightly:

    • Regular expression URLs with a . are now converted to path() syntax.

      Thanks to Iteron-dev for the report in Issue #567.

    • Invalid group names are no longer converted to path() syntax.

    PR #584.

1.26.0 (2025-08-26)

  • Add --check option that only reports which files would be changed.

    Thanks to berzi in PR #581.

  • Improve stdin handling: exit with code 0 even when changes were made for stdin, and print all other output to stderr.

    PR #583.

  • Fix the request_headers fixer for non-string in comparisons like 1 in request.META (unlikely in real code).

    PR #579.

1.25.0 (2025-05-13)

  • Add support for class-based settings files in the use_l10n fixer.

1.24.0 (2025-03-27)

  • Parse target Django version from pyproject.toml. Now, if you don’t specify a version with --target-version, django-upgrade will try to parse your minimum-supported target Django version from project.dependencies in pyproject.toml. It supports several common formats, like django>=5.2,<6.0.

    PR #543.

  • Add Django 5.2+ fixer postgres_aggregate_order_by to rewrite PostgreSQL aggregate functions using the old argument name ordering to the new name order_by.

    Issue #538.

  • Add Django 5.2+ fixer staticfiles_find_all to rewrite calls to the staticfiles find() function using the old argument name all to the new name find_all.

    Issue #539.

  • Restore Django 5.0+ fixer model_field_choices, with a restriction to only apply when the enumeration type is defined in the same file.

    Thanks to Thibaut Decombe for initially contributing it in PR #369.

  • Add Django 2.0+ compatibility import rewrite of django.http.cookie.SimpleCookie to http.cookies.SimpleCookie.

    Thanks to Thibaut Decombe in PR #537.

1.23.1 (2025-02-07)

  • Fix django_urls fixer bug that failed for indented path strings. This bug was introduced in 1.23.0.

    Thanks to Michal Čihař for the report in Issue #528.

1.23.0 (2025-02-06)

  • Support Django 5.2 in --target-version.

  • Extend versioned block fixer to support comparisons with single-item tuples, like django.VERSION >= (4,).

    Thanks to Thibaut Decombe in PR #517.

  • Fix versioned_test_skip_decorators fixer to remove all indentation tokens from the decorator line.

    Thanks to Thibaut Decombe in PR #518.

  • Fix django_urls fixer handling of implicitly concatenated strings.

    Thanks to Gunther Waidacher for the report in Issue #524.

1.22.2 (2024-12-02)

1.22.1 (2024-10-11)

  • Fix circular import error when running django-upgrade.

    Thanks to Michal Čihař for the report in Issue #503.

1.22.0 (2024-10-10)

  • Avoid accidental removal of comments a removed if block in the versioned block fixer.

    Thanks to Tobias Funke for the report in Issue #495.

  • Add all-version fixer to remove outdated test skip decorators.

    Issue #364.

  • Drop Python 3.8 support.

  • Support Python 3.13.

1.21.0 (2024-09-05)

  • Add Django 5.0+ fixer to rewrite format_html() calls without args or kwargs probably using str.format() incorrectly.

    Issue #477.

1.20.0 (2024-07-19)

  • Fix the admin_register fixer to avoid rewriting when there are duplicate ModelAdmin classes in the file.

    Issue #471.

1.19.0 (2024-06-27)

  • Add Django 4.2+ fixer to rewrite index_together declarations into indexes declarations in model Meta classes. This fixer can make changes that require migrations. Add a test for pending migrations to ensure that you do not miss these.

    PR #464.

  • Fix tracking of AST node parents. This may have fixed some subtle bugs in these fixers:

    • admin_register

    • assert_form_error

    • default_app_config

    • management_commands

    • request_headers

    • settings_database_postgresql

    • settings_storages

    • testcase_databases

    • use_l10n

    • utils_timezone

    If you see any new changes, or had them previously disabled, please report an issue so we can extra tests to the test suite.

    PR #465.

1.18.0 (2024-05-28)

  • Support Django 5.1 as a target version.

  • Add Django 5.1+ fixer to rewrite the check keyword argument of CheckConstraint to condition.

1.17.0 (2024-05-10)

  • Add fixer selection options: --only <name>, --skip <name>, and --list-fixers.

    Thanks to Gav O’Connor and David Szotten in PR #443.

  • Run per-file conditions once, yielding a performance improvement of ~2% measured on a real-world project.

1.16.0 (2024-02-11)

  • Remove the Django 5.0+ fixer that dropped .choices from model field choices parameters. It was too unreliable because it could break use for “DIY” enumeration types.

    Thanks to Niccolò Mineo and washeck for reporting in Issue #417.

  • Add Django 1.10+ fixer to rewrite request.user functions that changed to boolean attributes: is_authenticated and is_anonymous.

    Thanks to Alessandro Ferrini in PR #423.

  • Add Django 2.0+ imports fixes for names moved from django.core.urlresolvers to django.urls.

    Thanks to Thibaut Decombe in PR #404.

1.15.0 (2023-09-24)

  • Support Django 5.0 as a target version.

  • Add Django 5.0+ fixer to drop .choices on model field choices parameters when using an enumeration type.

    Thanks to Thibaut Decombe in PR #369.

  • Add some compatibility import replacements for Django 4.0 and below.

    Thanks to Thibaut Decombe in PR #368.

  • Fix issue with @admin.register() checker

    Thanks to Jan Pieter Waagmeester for the report in Issue #337, and to Thibaut Decombe for the review in PR #338.

1.14.1 (2023-08-16)

  • Fix bug in STORAGES fixer when only one of DEFAULT_FILE_STORAGE or STATICFILES_STORAGE was defined.

    Thanks to Bruno Alla in PR #376.

1.14.0 (2023-06-14)

  • Support Python 3.12.

1.13.0 (2023-02-17)

  • Add Django 4.2+ fixer to combine deprecated DEFAULT_FILE_STORAGE and STATICFILES_STORAGE settings into the new STORAGES setting.

  • Add Django 4.2+ fixer to rewrite HTTP headers passed to test Client and RequestFactory.

    Thanks to David Wobrock in PR #305.

  • Add Django 4.2+ fixer to rewrite test case methods assertFormsetError() and assertQuerysetEqual() into the new spellings with capitalized “Set”.

    Thanks to Michael Howitz in PR #253.

  • Add Django 4.0 fixer to rewrite django.contrib.admin.utils.lookup_needs_distinct -> lookup_spawns_duplicates.

    Thanks to Bruno Alla in PR #313.

  • Rewrite request.META -> request.headers on the right hand side of assignments.

  • Group some compatibility import replacements into a single “fixer”, optimizing runtime by about 3%.

    Thanks to Thibaut Decombe in PR #295.

1.12.0 (2022-11-09)

  • Make re_path -> path fixer also convert include()'s with unterminated regexes.

    Thanks to Thibaut Decombe in PR #279.

  • Avoid rewriting request.META to request.headers in del statements. This pattern works for request.META but not for request.headers which is an immutable mapping.

    Thanks to Thibaut Decombe in PR #290.

  • Add Django 1.9+ fixer to rename the legacy engine name django.db.backends.postgresql_psycopg2 in settings.DATABASES to django.db.backends.postgresql.

    Thanks to Thibaut Decombe in PR #280.

  • Make detection of management commands and migration files detect both forward and backward slashes as directory separators.

    Thanks to William Claassen in PR #286.

1.11.0 (2022-10-26)

See also the release blog post.

  • Add Django 1.7+ fixer to rewrite admin.site.register() calls into @admin.register() when eligible.

    Thanks to Thibaut Decombe in PR #189.

  • Add Django 3.2+ fixer to rewrite admin action function attributes to use the @admin.action() decorator.

  • Add Django 3.2+ fixer to rewrite admin display function attributes to use the @admin.display() decorator.

  • Add Django 4.1+ fixer to rewrite calls to test case methods assertFormError() and assertFormsetError() from their old signatures to the new ones.

  • Add Django 2.0+ fixer to drop assignments of allow_tags attributes to True.

  • Add Django 3.1+ fixer to replace list error message key with list_invalid on ModelMultipleChoiceField.

    Thanks to Thibaut Decombe in PR #258.

  • Make request.headers fixer also rewrite accesses of the content-length and content-type headers.

    Thanks to Christian Bundy in PR #226.

  • Extend request.headers fixer to rewrite in and not in comparisons on request.META.

    Thanks to Daan Vielen in Issue #234.

  • The request.headers fixer now uses lowercase for header lookups, as per the HTTP/2 specification.

  • Make on_delete fixer also support ForeignKey and OneToOneField imported from django.db.models.

    Thanks to Thibaut Decombe in PR #236.

  • Make NullBooleanField fixer preserve existing null arguments.

    Thanks to Joseph Zammit in Issue #245.

  • Update timezone.utc fixer to only use absolute references from existing imports of the datetime module.

  • Make Django 2.0+ URL fixer avoid a loop of adding imports that already exist.

    Thanks to Benjamin Bach for the report in Issue #250, and to Thibaut Decombe for the fix in PR #270.

  • Fixers that modify string literals now match existing use of double quotes.

    Thanks to Kevin Marsh in PR #260.

  • Make fixers that erase lines also erase any trailing comments.

  • Fix leaving a trailing comma when editing imports in certain cases.

  • Expand the range of files considered settings files.

  • Require at least one filename.

    Thanks to Daan Vielen in Issue #238.

  • Update README with info on how to run an upgrade on entire project.

    Thanks to Daan Vielen in Issue #240.

1.10.0 (2022-09-07)

  • Add Django 3.2+ fixer to update requires_system_checks in management command classes.

    Thanks to Bruno Alla in PR #184.

1.9.0 (2022-08-25)

  • Add Django 4.0+ fixer to remove USE_L10N = True setting.

    Thanks to Johnny Metz in PR #173.

  • Add fixer to remove outdated blocks based on comparing django.VERSION to old versions:

    -if django.VERSION > (4, 1):
    -    constraint.validate()
    +constraint.validate()
    
  • Update Django 2.0+ URL fixer to rewrite re_path() calls into path() when eligible.

    Thanks to Thibaut Decombe in PR #167.

1.8.1 (2022-08-25)

  • Fix timezone.utc fixer to import and use timezone.utc correctly.

    Thanks to Víðir Valberg Guðmundsson for the report in Issue #172.

1.8.0 (2022-08-11)

  • Support Django 4.1 as a target version.

  • Add Django 4.1+ fixer to rewrite imports of utc from django.utils.timezone to use datetime.timezone.

    Thanks to Hasan Ramezani in PR #169.

1.7.0 (2022-05-11)

  • Support Python 3.11.

1.6.1 (2022-05-04)

  • Fix default_app_config fixer to work with __init__.py files in subdirectories.

    Thanks to Bruno Alla in PR #144.

  • Add --version flag.

    Thanks to Ferran Jovell in PR #143.

1.6.0 (2022-05-04)

  • Add Django 3.2+ fixer to remove default_app_config assignments in __init__.py files.

    Thanks to Bruno Alla in PR #140.

1.5.0 (2022-04-14)

  • Fix URL rewriting to avoid converting regular expressions that don’t end with $. If the $ is missing, Django will search for the given regular expression anywhere in the path.

    Thanks to qdufrois for the report in Issue #121.

  • Made JSONField and NullBooleanField fixers ignore migrations files. Django kept these old field classes around for use in historical migrations, so there’s no need to rewrite such cases.

    Thanks to Matthieu Rigal and Bruno Alla for the report in Issue #79.

1.4.0 (2021-10-23)

  • Add Django 2.0+ fixer to rewrite imports of lru_cache from django.utils.functional to use functools.

  • Support Django 4.0 as a target version. There are no fixers for it at current. Most of its deprecations don’t seem automatically fixable.

1.3.2 (2021-09-23)

  • Avoid rewriting request.META to request.headers in assignments. This pattern is used in tests, and works for request.META but not request.headers.

    Thanks to Bruno Alla for the report in Issue #74.

1.3.1 (2021-09-22)

  • Fix import fixers to not crash on star imports (from foo import *).

    Thanks to Mikhail for the report in Issue #70.

1.3.0 (2021-09-22)

  • Fix get_random_string() fixer to not add the argument to calls like crypto.get_random_string(12).

  • Add fixers to remove various compatibility imports removed in Django 3.1.

    Thanks to Bruno Alla in PR #44.

  • Add fixer for Django 2.2 to rewrite request.META access of headers to HttpRequest.headers.

  • Add fixer for Django 2.0 to rewrite include() and url() from django.conf.urls to django.urls. url() may be rewritten to path() or re_path() accordingly.

    Thanks to Bruno Alla for the original implementation of regex-to-path conversion in django-codemod. Thanks to Matthias Kestenholz for an initial PR.

  • Add fixer for Django 1.9 requirement to pass on_delete to ForeignKey and OneToOneField.

    Thanks to Bruno Alla in PR #61.

1.2.0 (2021-09-02)

  • Support Python 3.10.

  • Support single level module imports of names too, such as using o from django.utils import crypto with crypto.get_random_string().

  • Add fixer for Django 3.1 deprecation of NullBooleanField.

  • Add fixers for Django 3.0 deprecation of functions in django.utils.http, django.utils.text, and django.utils.translation.

  • Add fixer for Django 2.2 rename of FloatRangeField to DecimalRangeField.

  • Add fixer for Django 2.2 deprecation of test case attributes allow_database_queries and multi_db.

  • Fix inserted imports to match indentation of the point they are inserted.

1.1.0 (2021-08-28)

  • Add fixer for Django 3.1 JSONField moves.

  • Add fixer for Django 3.1 removal of Signal’s argument providing_args.

  • Add fixer for Django 3.1 requirement to pass get_random_string() the length argument.

  • Fix Python 3.8 compatibility.

  • Drop Python 3.6 and 3.7 support, since they never worked, and the incompatibilities in the ast module are hard to cover.

1.0.0 (2021-08-27)

  • Initial release.