自动升级您的Django项目代码。
项目描述
自动升级您的Django项目代码。
通过我的书 提升您的Django开发体验 提高您的代码质量,该书涵盖了使用 pre-commit、django-upgrade 以及许多其他工具。我在编写这本书时创建了 django-upgrade!
安装
使用 pip
python -m pip install django-upgrade
支持Python 3.8到3.12。
(Python 3.12+ 是正确应用 f-strings 中修复所必需的。)
pre-commit 钩子
您还可以将 django-upgrade 作为 pre-commit 钩子安装。将以下内容添加到您的 repos 部分的 .pre-commit-config.yaml 文件中(在文档中),在所有代码格式化程序(如Black)之前
- repo: https://github.com/adamchainz/django-upgrade
rev: "" # replace with latest tag on GitHub
hooks:
- id: django-upgrade
args: [--target-version, "5.0"] # Replace with Django version
然后,升级您的整个项目
pre-commit run django-upgrade --all-files
提交任何更改。在此过程中,您的其他钩子将运行,可能会重新格式化 django-upgrade 的更改以匹配您的项目代码风格。
为了升级项目中添加的所有代码,请保留钩子安装。pre-commit 的 autoupdate 命令还可以让您利用 django-upgrade 的未来功能。
用法
django-upgrade 是一个命令行工具,用于原地重写文件。将您的 Django 版本作为 <major>.<minor> 格式传递给 --target-version 标志和文件列表。django-upgrade 的修复器将重写您的代码以避免 DeprecationWarning 并使用一些新功能。
例如
django-upgrade --target-version 5.0 example/core/models.py example/settings.py
django-upgrade 专注于升级您的代码,而不是使其看起来很漂亮。在像 Black 这样的格式化程序之前运行 django-upgrade。
django-upgrade 的某些修复器会修改需要迁移的模型
index_together
null_boolean_field
添加一个 测试挂起迁移 以确保您不会错过这些。
django-upgrade 没有递归遍历目录的能力。使用 pre-commit 集成、globbing 或其他技术来应用多个文件。一些修复器依赖于包含目录的名称来激活,因此请确保您以项目根目录相对路径运行 django-upgrade。例如,使用 git ls-files | xargs
git ls-files -z -- '*.py' | xargs -0 django-upgrade --target-version 5.0
…或者 PowerShell 的 ForEach-Object
git ls-files -- '*.py' | %{django-upgrade --target-version 5.0 $_}
修复器的完整列表如下。
选项
--target-version
目标 Django 版本,格式为 <major>.<minor>。django-upgrade 启用其修复器以支持目标版本及以下的所有版本。
此选项默认为 2.2,这是项目创建时支持的最旧版本。有关可用版本的列表,请参阅 django-upgrade --help。
--exit-zero-even-if-changed
即使文件已更改,也以零返回代码退出。默认情况下,如果 django-upgrade 更改了任何文件,它将使用失败返回代码 1,这可能会停止脚本或 CI 流水线。
--only <fixer_name>
仅运行命名的修复器(名称见下文)。修复器必须通过 --target-version 启用。使用多个 --only 选项选择多个修复器。
例如
django-upgrade --target-version 5.0 --only admin_allow_tags --only admin_decorators example/core/admin.py
--skip <fixer_name>
跳过命名的修复器。使用多个 --skip 选项跳过多个修复器。
例如
django-upgrade --target-version 5.0 --skip admin_register example/core/admin.py
--list-fixers
列出所有可用的修复器名称,然后退出。列出修复器时忽略所有其他选项。
例如
django-upgrade --list-fixers
历史
django-codemod 是一个现有的、更完整的 Django 自动升级工具,由 Bruno Alla 编写。不幸的是,其底层库 LibCST 特别慢,使得在每次提交和 CI 中运行 django-codemod 都很烦人。
django-upgrade 是一个实验,使用与神奇的 pyupgrade 相同的技术重新实现此类工具。该工具依赖于标准库的 ast 和 tokenize 模块,后者通过 tokenize-rt 包装器。这意味着它始终很快,并支持 Python 的最新版本。
快速基准测试:运行 django-codemod 对一个中等大小的 Django 代码库进行测试,该代码库有 153k 行 Python 代码,耗时 133 秒。pyupgrade 和 django-upgrade 都不到 0.5 秒。
修复器
所有版本
以下修复器不受目标版本的影响。
版本化块
名称: versioned_branches
从比较 django.VERSION 的 if 语句中删除过时的比较和块。支持以下形式的比较
if django.VERSION <comparator> (<X>, <Y>):
...
其中 <comparator> 是 <、<=、> 或 >= 中的一个,而 <X> 和 <Y> 是整数字面量。可以存在单个 else 块,但不支持 elif。
-if django.VERSION < (4, 1):
- class RenameIndex:
- ...
-if django.VERSION >= (4, 1):
- constraint.validate()
-else:
- custom_validation(constraint)
+constraint.validate()
另请参阅pyupgrade 的类似功能,该功能从对 Python 版本的检查中删除了过时代码。
Django 5.1
CheckConstraint 条件参数
名称: check_constraint_condition
将调用旧 check 参数的 CheckConstraint 和内置子类的旧名称重写为新名称 condition。
由于 ast.keyword 的更改,需要 Python 3.9+。
-CheckConstraint(check=Q(amount__gte=0))
+CheckConstraint(condition=Q(amount__gte=0))
Django 5.0
format_html() 调用
名称: format_html
重写没有 args 或 kwargs 但使用 str.format() 的 format_html() 调用。这种调用很可能错误地应用了未转义的格式化,使其容易受到 HTML 注入的攻击。这就是为什么在 问题 #34609 中弃用了不带任何参数或关键字参数的 format_html() 调用的原因。
from django.utils.html import format_html
-format_html("<marquee>{}</marquee>".format(message))
+format_html("<marquee>{}</marquee>", message)
-format_html("<marquee>{name}</marquee>".format(name=name))
+format_html("<marquee>{name}</marquee>", name=name)
Django 4.2
STORAGES 设置
名称: settings_storages
将过时的设置 DEFAULT_FILE_STORAGE 和 STATICFILES_STORAGE 合并到新的 STORAGES 设置中,在设置文件中。仅当所有旧设置都定义为字符串,在模块级别,并且没有定义 STORAGES 设置时才适用。
设置文件被启发式地检测为路径中包含整个单词“settings”的模块。例如 myproject/settings.py 或 myproject/settings/production.py。
-DEFAULT_FILE_STORAGE = "example.storages.ExtendedFileSystemStorage"
-STATICFILES_STORAGE = "example.storages.ExtendedS3Storage"
+STORAGES = {
+ "default": {
+ "BACKEND": "example.storages.ExtendedFileSystemStorage",
+ },
+ "staticfiles": {
+ "BACKEND": "example.storages.ExtendedS3Storage",
+ },
+}
如果模块有一个 from ... import *,其中模块路径包含“settings”,则 django-upgrade 会据此推测从中导入了基本 STORAGES 设置。然后它使用 ** 来扩展当前模块中的任何值
from example.settings.base import *
-DEFAULT_FILE_STORAGE = "example.storages.S3Storage"
+STORAGES = {
+ **STORAGES,
+ "default": {
+ "BACKEND": "example.storages.S3Storage",
+ },
+}
测试客户端 HTTP 标头
名称: test_http_headers
将 HTTP 标头从旧的 WSGI 关键字参数格式转换为使用新的 headers 字典,用于
Client 方法,如 self.client.get()
Client 实例化
RequestFactory 实例化
由于 ast.keyword 的更改,需要 Python 3.9+。
-response = self.client.get("/", HTTP_ACCEPT="text/plain")
+response = self.client.get("/", headers={"accept": "text/plain"})
from django.test import Client
-Client(HTTP_ACCEPT_LANGUAGE="fr-fr")
+Client(headers={"accept-language": "fr-fr"})
from django.test import RequestFactory
-RequestFactory(HTTP_USER_AGENT="curl")
+RequestFactory(headers={"user-agent": "curl"})
index_together 弃用
名称: index_together
将 index_together 声明重写到模型 Meta 类中的 indexes 声明中。
from django.db import models
class Duck(models.Model):
class Meta:
- index_together = [["bill", "tail"]]
+ indexes = [models.Index(fields=["bill", "tail"])]
assertFormsetError 和 assertQuerysetEqual
名称: assert_set_methods
将这些测试用例方法的调用从旧名称重写到使用大写“Set”的新名称。
-self.assertFormsetError(response.context["form"], "username", ["Too long"])
+self.assertFormSetError(response.context["form"], "username", ["Too long"])
-self.assertQuerysetEqual(authors, ["Brad Dayley"], lambda a: a.name)
+self.assertQuerySetEqual(authors, ["Brad Dayley"], lambda a: a.name)
Django 4.1
django.utils.timezone.utc 弃用
名称: utils_timezone
将 django.utils.timezone.utc 的导入重写为使用 datetime.timezone.utc。需要现有 datetime 模块的导入。
import datetime
-from django.utils.timezone import utc
-calculate_some_datetime(utc)
+calculate_some_datetime(datetime.timezone.utc)
import datetime as dt
from django.utils import timezone
-do_a_thing(timezone.utc)
+do_a_thing(dt.timezone.utc)
assertFormError() 和 assertFormsetError()
名称: assert_form_error
将对这些测试用例方法的旧签名调用重写为新签名。
-self.assertFormError(response, "form", "username", ["Too long"])
+self.assertFormError(response.context["form"], "username", ["Too long"])
-self.assertFormError(response, "form", "username", None)
+self.assertFormError(response.context["form"], "username", [])
-self.assertFormsetError(response, "formset", 0, "username", ["Too long"])
+self.assertFormsetError(response.context["formset"], 0, "username", ["Too long"])
-self.assertFormsetError(response, "formset", 0, "username", None)
+self.assertFormsetError(response.context["formset"], 0, "username", [])
Django 4.0
USE_L10N
名称: use_l10n
如果设置为默认值 True,则删除已弃用的 USE_L10N 设置。
设置文件被启发式地检测为路径中包含整个单词“settings”的模块。例如 myproject/settings.py 或 myproject/settings/production.py。
-USE_L10N = True
lookup_needs_distinct
名称: admin_lookup_needs_distinct
将未记录的 django.contrib.admin.utils.lookup_needs_distinct 重命名为 lookup_spawns_duplicates。
-from django.contrib.admin.utils import lookup_needs_distinct
+from django.contrib.admin.utils import lookup_spawns_duplicates
-if lookup_needs_distinct(self.opts, search_spec):
+if lookup_spawns_duplicates(self.opts, search_spec):
...
兼容性导入
重写一些兼容性导入。
django.utils.translation.template.TRANSLATOR_COMMENT_MARK 在 django.template.base
-from django.template.base import TRANSLATOR_COMMENT_MARK
+from django.utils.translation.template import TRANSLATOR_COMMENT_MARK
Django 3.2
@admin.action()
名称: admin_decorators
将具有管理员操作属性分配给函数的重写为使用新的 @admin.action() 装饰器。这仅适用于使用 from django.contrib import admin 或 from django.contrib.gis import admin 的文件。
from django.contrib import admin
# Module-level actions:
+@admin.action(
+ description="Publish articles",
+)
def make_published(modeladmin, request, queryset):
...
-make_published.short_description = "Publish articles"
# …and within classes:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
+ @admin.action(
+ description="Unpublish articles",
+ permissions=("unpublish",),
+ )
def make_unpublished(self, request, queryset):
...
- make_unpublished.allowed_permissions = ("unpublish",)
- make_unpublished.short_description = "Unpublish articles"
@admin.display()
名称: admin_decorators
将具有管理员显示属性分配给函数的重写为使用新的 @admin.display() 装饰器。这仅适用于使用 from django.contrib import admin 或 from django.contrib.gis import admin 的文件。
from django.contrib import admin
# Module-level display functions:
+@admin.display(
+ description="NAME",
+)
def upper_case_name(obj):
...
-upper_case_name.short_description = "NAME"
# …and within classes:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
+ @admin.display(
+ description='Is Published?',
+ boolean=True,
+ ordering='-publish_date',
+ )
def is_published(self, obj):
...
- is_published.boolean = True
- is_published.admin_order_field = '-publish_date'
- is_published.short_description = 'Is Published?'
BaseCommand.requires_system_checks
名称: management_commands
将管理命令类中的 requires_system_checks 属性从布尔值重写为 "__all__" 或 [],根据需要。这仅适用于命令文件,这些文件被启发式地检测为路径中包含 management/commands 的文件。
from django.core.management.base import BaseCommand
class Command(BaseCommand):
- requires_system_checks = True
+ requires_system_checks = "__all__"
class SecondCommand(BaseCommand):
- requires_system_checks = False
+ requires_system_checks = []
EmailValidator
名称: email_validator
将关键字参数 whitelist 重命名为新名称 allowlist。
from django.core.validators import EmailValidator
-EmailValidator(whitelist=["example.com"])
+EmailValidator(allowlist=["example.com"])
default_app_config
名称: default_app_config
从 __init__.py 文件中删除模块级 default_app_config 赋值。
-default_app_config = 'my_app.apps.AppConfig'
Django 3.1
JSONField
名称: compatibility_imports
将 JSONField 和相关转换类的导入从 django.contrib.postgres 重写为新数据库版本。忽略迁移文件中的使用,因为 Django 保留旧类以支持旧迁移。在修复更改模型后,您将需要创建迁移。
-from django.contrib.postgres.fields import JSONField
+from django.db.models import JSONField
PASSWORD_RESET_TIMEOUT_DAYS
名称: password_reset_timeout_days
将设置 PASSWORD_RESET_TIMEOUT_DAYS 重写为 PASSWORD_RESET_TIMEOUT,并添加乘以一天中的秒数。
设置文件被启发式地检测为路径中包含整个单词“settings”的模块。例如 myproject/settings.py 或 myproject/settings/production.py。
-PASSWORD_RESET_TIMEOUT_DAYS = 4
+PASSWORD_RESET_TIMEOUT = 60 * 60 * 24 * 4
Signal
名称: signal_providing_args
删除仅文档化的已弃用 providing_args 参数。
from django.dispatch import Signal
-my_cool_signal = Signal(providing_args=["documented", "arg"])
+my_cool_signal = Signal()
get_random_string
名称: crypto_get_random_string
注入现在必需的 length 参数,其之前的默认值为 12。
from django.utils.crypto import get_random_string
-key = get_random_string(allowed_chars="01234567899abcdef")
+key = get_random_string(length=12, allowed_chars="01234567899abcdef")
NullBooleanField
名称: null_boolean_field
将模型字段 NullBooleanField() 转换为 BooleanField(null=True)。仅在模型文件中应用,不在迁移文件中应用,因为 Django 保留旧类以支持旧迁移。在修复更改模型后,您将需要创建迁移。
-from django.db.models import Model, NullBooleanField
+from django.db.models import Model, BooleanField
class Book(Model):
- valuable = NullBooleanField("Valuable")
+ valuable = BooleanField("Valuable", null=True)
ModelMultipleChoiceField
名称: forms_model_multiple_choice_field
在表单 ModelMultipleChoiceField 中,将 list 错误信息键替换为 list_invalid。
-forms.ModelMultipleChoiceField(error_messages={"list": "Enter multiple values."})
+forms.ModelMultipleChoiceField(error_messages={"invalid_list": "Enter multiple values."})
Django 3.0
django.utils.encoding 别名
名称: utils_encoding
将 smart_text() 重写为 smart_str(),将 force_text() 重写为 force_str()。
-from django.utils.encoding import force_text, smart_text
+from django.utils.encoding import force_str, smart_str
-force_text("yada")
-smart_text("yada")
+force_str("yada")
+smart_str("yada")
django.utils.http 弃用
名称: utils_http
将 urlquote()、urlquote_plus()、urlunquote() 和 urlunquote_plus() 函数重写为 urllib.parse 版本。还将内部函数 is_safe_url() 重写为 url_has_allowed_host_and_scheme()。
-from django.utils.http import urlquote
+from urllib.parse import quote
-escaped_query_string = urlquote(query_string)
+escaped_query_string = quote(query_string)
django.utils.text 弃用
名称: utils_text
使用标准库 html.escape() 重写了 unescape_entities()。
-from django.utils.text import unescape_entities
+import html
-unescape_entities("some input string")
+html.escape("some input string")
django.utils.translation 弃用
名称: utils_translation
将 ugettext()、ugettext_lazy()、ugettext_noop()、ungettext() 和 ungettext_lazy() 函数重写为它们的非-u-前缀版本。
-from django.utils.translation import ugettext as _, ungettext
+from django.utils.translation import gettext as _, ngettext
-ungettext("octopus", "octopodes", n)
+ngettext("octopus", "octopodes", n)
Django 2.2
HttpRequest.headers
名称: request_headers
将使用 request.META 读取 HTTP 头部信息重写为使用 request.headers。根据 HTTP/2 规范,头部查找将转换为小写。
-request.META['HTTP_ACCEPT_ENCODING']
+request.headers['accept-encoding']
-self.request.META.get('HTTP_SERVER', '')
+self.request.headers.get('server', '')
-request.META.get('CONTENT_LENGTH')
+request.headers.get('content-length')
-"HTTP_SERVER" in request.META
+"server" in request.headers
QuerySetPaginator
名称: queryset_paginator
将弃用的别名 django.core.paginator.QuerySetPaginator 重写为 Paginator。
-from django.core.paginator import QuerySetPaginator
+from django.core.paginator import Paginator
-QuerySetPaginator(...)
+Paginator(...)
FixedOffset
名称: timezone_fixedoffset
将弃用的类 FixedOffset(x, y)) 重写为 timezone(timedelta(minutes=x), y)。
已知限制:如果使用仅含 *args 或 **kwargs 的 FixedOffset 调用,则此修正器将使代码损坏并产生 ImportError。
-from django.utils.timezone import FixedOffset
-FixedOffset(120, "Super time")
+from datetime import timedelta, timezone
+timezone(timedelta(minutes=120), "Super time")
FloatRangeField
名称: postgres_float_range_field
将使用 FloatRangeField 的模型和表单字段重写为 DecimalRangeField,从相关的 django.contrib.postgres 模块。
from django.db.models import Model
-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 类数据库声明
名称: testcase_databases
将 Django 的 TestCase 类的 allow_database_queries 和 multi_db 属性重写为新的 databases 属性。这仅适用于测试文件,这些文件通过其路径中的“test”或“tests”位置进行启发式检测。
注意,这将仅重写为 databases = [] 或 databases = "__all__"。在多个数据库的情况下,可以通过限制测试案例到它们所需的数据库来节省一些测试时间(这就是为什么 Django 进行了更改)。
from django.test import SimpleTestCase
class MyTests(SimpleTestCase):
- allow_database_queries = True
+ databases = "__all__"
def test_something(self):
self.assertEqual(2 * 2, 4)
Django 2.1
目前还没有修正器。
Django 2.0
URL
名称: django_urls
将 include() 和 url() 的导入从 django.conf.urls 重写为 django.urls。使用兼容正则表达式的 url() 调用被重写为新的 path() 语法,否则转换为调用 re_path()。
-from django.conf.urls import include, url
+from django.urls import include, path, re_path
urlpatterns = [
- url(r'^$', views.index, name='index'),
+ path('', views.index, name='index'),
- url(r'^about/$', views.about, name='about'),
+ path('about/', views.about, name='about'),
- url(r'^post/(?P<slug>[-a-zA-Z0-9_]+)/$', views.post, name='post'),
+ path('post/<slug:slug>/', views.post, name='post'),
- url(r'^weblog', include('blog.urls')),
+ re_path(r'^weblog', include('blog.urls')),
]
现有的 re_path() 调用在符合条件时也会重写为 path() 语法。
-from django.urls import include, re_path
+from django.urls import include, path, re_path
urlpatterns = [
- re_path(r'^about/$', views.about, name='about'),
+ path('about/', views.about, name='about'),
re_path(r'^post/(?P<slug>[\w-]+)/$', views.post, name='post'),
]
以下是将转换为使用 path converters 的兼容正则表达式:
[^/]+ → str
[0-9]+ → int
[-a-zA-Z0-9_]+ → slug
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} → uuid
.+ → path
这些来自路径转换类。
在某些情况下,此更改会改变传递给视图的参数类型,从 str 更改为转换类型(例如 int)。这不能保证向后兼容:有可能会出现视图期望字符串而不是转换类型的情况。但是,从实用主义的角度来看,似乎有 99.9% 的视图不需要字符串,而是使用字符串或转换类型。因此,你应该在修复器进行任何更改后测试受影响的路径。
注意,[\w-] 有时用于 slug,但它不会被转换,因为它可能不兼容。该模式匹配所有 Unicode 单词字符,如“α”,而 Django 的 slug 转换器仅匹配拉丁字符。
lru_cache
名称: compatibility_imports
将 lru_cache 的导入从 django.utils.functional 重写为使用 functools。
-from django.utils.functional import lru_cache
+from functools import lru_cache
ContextDecorator
将 ContextDecorator 的导入从 django.utils.decorators 重写为使用 contextlib。
-from django.utils.decorators import ContextDecorator
+from contextlib import ContextDecorator
Django 1.11
兼容性导入
名称: compatibility_imports
重写一些兼容性导入。
django.core.exceptions.EmptyResultSet 在 django.db.models.query,django.db.models.sql 和 django.db.models.sql.datastructures
django.core.exceptions.FieldDoesNotExist 在 django.db.models.fields
尽管在 Django 3.1 发布说明 中提到,但这些功能自 Django 1.11 以来一直是可能的。
-from django.db.models.query import EmptyResultSet
+from django.core.exceptions import EmptyResultSet
-from django.db.models.fields import FieldDoesNotExist
+from django.core.exceptions import FieldDoesNotExist
Django 1.10
request.user 布尔属性
名称: request_user_attributes
按照 弃用说明,重写了 request.user.is_authenticated() 和 request.user.is_anonymous() 的调用,去除了括号。
-request.user.is_authenticated()
+request.user.is_authenticated
-self.request.user.is_anonymous()
+self.request.user.is_anonymous
兼容性导入
重写一些兼容性导入。
django.templatetags.static.static 在 django.contrib.staticfiles.templatetags.staticfiles
(虽然在Django 2.1版本说明中提到过,但这一功能自Django 1.10以来就已经可能实现。)
django.urls.* 在 django.core.urlresolvers.*
-from django.contrib.staticfiles.templatetags.staticfiles import static
+from django.templatetags.static import static
-from django.core.urlresolvers import reverse
+from django.urls import reverse
-from django.core.urlresolvers import resolve
+from django.urls import resolve
Django 1.9
on_delete 参数
名称: on_delete
将 on_delete=models.CASCADE 添加到 ForeignKey 和 OneToOneField
from django.db import models
-models.ForeignKey("auth.User")
+models.ForeignKey("auth.User", on_delete=models.CASCADE)
-models.OneToOneField("auth.User")
+models.OneToOneField("auth.User", on_delete=models.CASCADE)
此修复程序还支持从导入
-from django.db.models import ForeignKey
+from django.db.models import CASCADE, ForeignKey
-ForeignKey("auth.User")
+ForeignKey("auth.User", on_delete=CASCADE)
DATABASES
名称: settings_database_postgresql
更新 DATABASES 设置的后端路径 django.db.backends.postgresql_psycopg2,以使用重命名的版本 django.db.backends.postgresql。
设置文件被启发式地检测为路径中包含整个单词“settings”的模块。例如 myproject/settings.py 或 myproject/settings/production.py。
DATABASES = {
"default": {
- "ENGINE": "django.db.backends.postgresql_psycopg2",
+ "ENGINE": "django.db.backends.postgresql",
"NAME": "mydatabase",
"USER": "mydatabaseuser",
"PASSWORD": "mypassword",
"HOST": "127.0.0.1",
"PORT": "5432",
}
}
兼容性导入
名称: compatibility_imports
重写一些兼容性导入。
django.forms.utils.pretty_name 在 django.forms.forms
django.forms.boundfield.BoundField 在 django.forms.forms
django.forms.widgets.SelectDateWidget 在 django.forms.extras
虽然在Django 3.1版本说明中提到过,但这些功能自Django 1.9以来就已经可能实现。
-from django.forms.forms import pretty_name
+from django.forms.utils import pretty_name
Django 1.8
目前还没有修正器。
Django 1.7
管理模型注册
名称: admin_register
当符合条件时,将 admin.site.register() 调用重写为新的 @admin.register() 装饰器语法。这仅适用于使用 from django.contrib import admin 或 from django.contrib.gis import admin 的文件。
from django.contrib import admin
+@admin.register(MyModel1, MyModel2)
class MyCustomAdmin(admin.ModelAdmin):
...
-admin.site.register(MyModel1, MyCustomAdmin)
-admin.site.register(MyModel2, MyCustomAdmin)
这也适用于自定义管理站点。此类调用基于以下三个标准进行启发式检测
被调用 register() 方法的对象名称以 site 结尾。
注册的类名称以 Admin 结尾。
文件名在其路径中包含单词 admin。
from myapp.admin import custom_site
from django.contrib import admin
+@admin.register(MyModel)
+@admin.register(MyModel, site=custom_site)
class MyModelAdmin(admin.ModelAdmin):
pass
-custom_site.register(MyModel, MyModelAdmin)
-admin.site.register(MyModel, MyModelAdmin)
如果 register() 调用之前有一个包含相同模型的 unregister() 调用,则忽略该调用。
from django.contrib import admin
class MyCustomAdmin(admin.ModelAdmin):
...
admin.site.unregister(MyModel1)
admin.site.register(MyModel1, MyCustomAdmin)
兼容性导入
重写一些兼容性导入。
django.contrib.admin.helpers.ACTION_CHECKBOX_NAME 在 django.contrib.admin
django.template.context.BaseContext、django.template.context.Context、django.template.context.ContextPopException 和 django.template.context.RequestContext 在 django.template.base
-from django.contrib.admin import ACTION_CHECKBOX_NAME
+from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
-from django.template.base import Context
+from django.template.context import Context
项目详情
下载文件
下载适用于您的平台文件。如果您不确定选择哪个,请了解更多关于安装软件包的信息。
源分发
构建分发
django_upgrade-1.21.0.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | e65021029e7d18b407bd128a8ccb31e5e06685068b37b6b1eaf2f77aa3d3df98 |
|
MD5 | fee7f621b62a41dd87b77fd0fdf6e7db |
|
BLAKE2b-256 | 2e305215e526e054831cbbc454ce81fb5e825224019824a185e3c011cf199b90 |
django_upgrade-1.21.0-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | a0a7b11d5108fb2d3038cea2382c1332c9be4ff5059a38357fbd28116ebf3803 |
|
MD5 | b9aa0b05c3a641edc84410b3b22cef7e |
|
BLAKE2b-256 | 56767a7eeb88657abf8a0f97fbab4f6600be2ec89577e3695c395b47e6860ec5 |