hramezani / django-upgrade

Automatically upgrade your Django projects.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

django-upgrade

image

image

image

image

pre-commit

Automatically upgrade your Django projects.

Installation

Use pip:

Python 3.8 to 3.11 supported.

Or with pre-commit in the repos section of your .pre-commit-config.yaml file (docs):


Want to improve your code quality? Check out my book Boost Your Django DX which covers using pre-commit, django-upgrade, and many other tools. I wrote django-upgrade whilst working on the book!


Usage

django-upgrade is a commandline tool that rewrites files in place. Pass your Django version as <major>.<minor> to the --target-version flag. The built-in fixers will rewrite your code to avoid some DeprecationWarnings and use some new features on your Django version. For example:

The --target-version flag defaults to 2.2, the oldest supported version when this project was created. For more on usage run django-upgrade --help.

django-upgrade focuses on upgrading your code and not on making it look nice. Run django-upgrade before formatters like Black.

django-upgrade does not have any ability to recurse through directories. Use the pre-commit integration, globbing, or another technique for applying to many files such as with git ls-files | xargs__.

The full list of fixers is documented below.

History

django-codemod is a pre-existing, more complete Django auto-upgrade tool, written by Bruno Alla. Unfortunately its underlying library LibCST is particularly slow, making it annoying to run django-codemod on every commit and in CI.

django-upgrade is an experiment in reimplementing such a tool using the same techniques as the fantastic pyupgrade. The tool leans on the standard library’s ast and tokenize modules, the latter via the tokenize-rt wrapper. This means it will always be fast and support the latest versions of Python.

For a quick benchmark: running django-codemod against a medium Django repository with 153k lines of Python takes 133 seconds. pyupgrade and django-upgrade both take less than 0.5 seconds.

Fixers

Django 1.9

Release Notes

on_delete argument

Add on_delete=models.CASCADE to ForeignKey and OneToOneField:

Compatibility imports

Rewrites some compatibility imports:

  • django.forms.utils.pretty_name in django.forms.forms
  • django.forms.boundfield.BoundField in django.forms.forms

Whilst mentioned in the Django 3.1 release notes, these have been possible since Django 1.9.

Django 1.11

Release Notes

Compatibility imports

Rewrites some compatibility imports:

  • django.core.exceptions.EmptyResultSet in django.db.models.query, django.db.models.sql, and django.db.models.sql.datastructures
  • django.core.exceptions.FieldDoesNotExist in django.db.models.fields

Whilst mentioned in the Django 3.1 release notes, these have been possible since Django 1.11.

Django 2.0

Release Notes

URL’s

Rewrites imports of include() and url() from django.conf.urls to django.urls. url() calls using compatible regexes are rewritten to the new path() syntax__, otherwise they are converted to call re_path().

lru_cache

Rewrites imports of lru_cache from django.utils.functional to use functools.

Django 2.2

Release Notes

HttpRequest.headers

Rewrites use of request.META to read HTTP headers to instead use request.headers__.

QuerySetPaginator

Rewrites deprecated alias django.core.paginator.QuerySetPaginator to Paginator.

FixedOffset

Rewrites deprecated class FixedOffset(x, y)) to timezone(timedelta(minutes=x), y)

Known limitation: this fixer will leave code broken with an ImportError if FixedOffset is called with only *args or **kwargs.

FloatRangeField

Rewrites model and form fields using FloatRangeField to DecimalRangeField, from the relevant django.contrib.postgres modules.

-from django.contrib.postgres.fields import FloatRangeField +from django.contrib.postgres.fields import DecimalRangeField

class MyModel(Model):

  • my_field = FloatRangeField("My range of numbers")
  • my_field = DecimalRangeField("My range of numbers")

TestCase class database declarations

Rewrites the allow_database_queries and multi_db attributes of Django’s TestCase classes to the new databases attribute. This only applies in test files, which are heuristically detected as files with either “test” or “tests” somewhere in their path.

Note that this will only rewrite to databases = [] or databases = "__all__". With multiple databases you can save some test time by limiting test cases to the databases they require (which is why Django made the change).

  • allow_database_queries = True
  • databases = "__all"
    def test_something(self):

    self.assertEqual(2 * 2, 4)

Django 3.0

Release Notes

django.utils.encoding aliases

Rewrites smart_text() to smart_str(), and force_text() to force_str().

django.utils.http deprecations

Rewrites the urlquote(), urlquote_plus(), urlunquote(), and urlunquote_plus() functions to the urllib.parse versions. Also rewrites the internal function is_safe_url() to url_has_allowed_host_and_scheme().

django.utils.text deprecation

Rewrites unescape_entities() with the standard library html.escape().

django.utils.translation deprecations

Rewrites the ugettext(), ugettext_lazy(), ugettext_noop(), ungettext(), and ungettext_lazy() functions to their non-u-prefixed versions.

Django 3.1

Release Notes

JSONField

Rewrites imports of JSONField and related transform classes from those in django.contrib.postgres to the new all-database versions. Ignores usage in migration files, since Django kept the old class around to support old migrations. You will need to make migrations after this fix makes changes to models.

PASSWORD_RESET_TIMEOUT_DAYS

Rewrites the setting PASSWORD_RESET_TIMEOUT_DAYS to PASSWORD_RESET_TIMEOUT, adding the multiplication by the number of seconds in a day.

Settings files are heuristically detected as modules with the whole word “settings” somewhere in their path. For example myproject/settings.py or myproject/settings/production.py.

Signal

Removes the deprecated documentation-only providing_args argument.

-my_cool_signal = Signal(providing_args=["documented", "arg"]) +my_cool_signal = Signal()

get_random_string

Injects the now-required length argument, with its previous default 12.

-key = get_random_string(allowed_chars="01234567899abcdef") +key = get_random_string(length=12, allowed_chars="01234567899abcdef")

NullBooleanField

Transforms the NullBooleanField() model field to BooleanField(null=True). Ignores usage in migration files, since Django kept the old class around to support old migrations. You will need to make migrations after this fix makes changes to models.

Django 3.2

Release Notes

EmailValidator

Rewrites keyword arguments to their new names: whitelist to allowlist, and domain_whitelist to domain_allowlist.

-EmailValidator(whitelist=["example.com"]) +EmailValidator(allowlist=["example.com"]) -EmailValidator(domain_whitelist=["example.org"]) +EmailValidator(domain_allowlist=["example.org"])

default_app_config

Removes module-level default_app_config assignments from __init__.py files:

Django 4.0

Release Notes

There are no fixers for Django 4.0 at current. Most of its deprecations don’t seem automatically fixable.

About

Automatically upgrade your Django projects.

License:MIT License


Languages

Language:Python 100.0%