diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 03fc5de90ab4..e37d7b5ee221 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -79,7 +79,7 @@ jobs: with: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@e673c3917a1aef3c65c972347ed84ccd013ecda4 # v0.2.0 + uses: zizmorcore/zizmor-action@e639db99335bc9038abc0e066dfcd72e23d26fb4 # v0.3.0 with: advanced-security: false annotations: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c7a51b961ecc..d1972c080070 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/psf/black-pre-commit-mirror - rev: 25.9.0 + rev: 25.12.0 hooks: - id: black exclude: \.py-tpl$ @@ -9,7 +9,7 @@ repos: hooks: - id: blacken-docs additional_dependencies: - - black==25.9.0 + - black==25.12.0 files: 'docs/.*\.txt$' args: ["--rst-literal-block"] - repo: https://github.com/PyCQA/isort @@ -21,10 +21,10 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-eslint - rev: v9.36.0 + rev: v9.39.1 hooks: - id: eslint - repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: v1.16.3 + rev: v1.19.0 hooks: - id: zizmor diff --git a/django/contrib/admin/checks.py b/django/contrib/admin/checks.py index 10257a54bf89..d14515e8a424 100644 --- a/django/contrib/admin/checks.py +++ b/django/contrib/admin/checks.py @@ -236,14 +236,20 @@ def _check_autocomplete_fields_item(self, obj, field_name, label): id="admin.E038", ) try: + if isinstance(field.remote_field.model, str): + raise NotRegistered related_admin = obj.admin_site.get_model_admin(field.remote_field.model) except NotRegistered: + # field.remote_field.model could be a string or a class. + remote_model = getattr( + field.remote_field.model, "__name__", field.remote_field.model + ) return [ checks.Error( 'An admin for model "%s" has to be registered ' "to be referenced by %s.autocomplete_fields." % ( - field.remote_field.model.__name__, + remote_model, type(obj).__name__, ), obj=obj.__class__, diff --git a/tests/modeladmin/test_checks.py b/tests/modeladmin/test_checks.py index fbd63abfbf15..c493148eb9cf 100644 --- a/tests/modeladmin/test_checks.py +++ b/tests/modeladmin/test_checks.py @@ -1724,6 +1724,28 @@ class Admin(ModelAdmin): invalid_obj=Admin, ) + @isolate_apps("modeladmin") + def test_autocomplete_e039_unresolved_model(self): + class UnresolvedForeignKeyModel(models.Model): + unresolved = models.ForeignKey("missing.Model", models.CASCADE) + + class Meta: + app_label = "modeladmin" + + class Admin(ModelAdmin): + autocomplete_fields = ("unresolved",) + + self.assertIsInvalid( + Admin, + UnresolvedForeignKeyModel, + msg=( + 'An admin for model "missing.Model" has to be registered ' + "to be referenced by Admin.autocomplete_fields." + ), + id="admin.E039", + invalid_obj=Admin, + ) + def test_autocomplete_e040(self): class NoSearchFieldsAdmin(ModelAdmin): pass