1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Fixed #34345 -- Added system check for ManyToManyFields with intermediate tables in ModelAdmin.filter_horizontal/vertical.

This commit is contained in:
Hrushikesh 2023-06-16 19:06:24 +05:30 committed by Mariusz Felisiak
parent ddb6506618
commit 107865780a
3 changed files with 56 additions and 4 deletions

View File

@ -533,6 +533,16 @@ class BaseModelAdminChecks:
return must_be(
"a many-to-many field", option=label, obj=obj, id="admin.E020"
)
elif not field.remote_field.through._meta.auto_created:
return [
checks.Error(
f"The value of '{label}' cannot include the ManyToManyField "
f"'{field_name}', because that field manually specifies a "
f"relationship model.",
obj=obj.__class__,
id="admin.E013",
)
]
else:
return []

View File

@ -637,9 +637,10 @@ with the admin site:
* **admin.E011**: The value of ``fieldsets[n][1]`` must contain the key
``fields``.
* **admin.E012**: There are duplicate field(s) in ``fieldsets[n][1]``.
* **admin.E013**: The value of ``fields[n]/fieldsets[n][m]`` cannot include the
``ManyToManyField`` ``<field name>``, because that field manually specifies a
relationship model.
* **admin.E013**: The value of
``fields[n]/filter_horizontal[n]/filter_vertical[n]/fieldsets[n][m]`` cannot
include the ``ManyToManyField`` ``<field name>``, because that field manually
specifies a relationship model.
* **admin.E014**: The value of ``exclude`` must be a list or tuple.
* **admin.E015**: The value of ``exclude`` contains duplicate field(s).
* **admin.E016**: The value of ``form`` must inherit from ``BaseModelForm``.

View File

@ -4,10 +4,11 @@ from django.contrib.admin import BooleanFieldListFilter, SimpleListFilter
from django.contrib.admin.options import VERTICAL, ModelAdmin, TabularInline
from django.contrib.admin.sites import AdminSite
from django.core.checks import Error
from django.db.models import CASCADE, F, Field, ForeignKey, Model
from django.db.models import CASCADE, F, Field, ForeignKey, ManyToManyField, Model
from django.db.models.functions import Upper
from django.forms.models import BaseModelFormSet
from django.test import SimpleTestCase
from django.test.utils import isolate_apps
from .models import Band, Song, User, ValidationTestInlineModel, ValidationTestModel
@ -321,6 +322,26 @@ class FilterVerticalCheckTests(CheckTestCase):
"admin.E020",
)
@isolate_apps("modeladmin")
def test_invalid_m2m_field_with_through(self):
class Artist(Model):
bands = ManyToManyField("Band", through="BandArtist")
class BandArtist(Model):
artist = ForeignKey("Artist", on_delete=CASCADE)
band = ForeignKey("Band", on_delete=CASCADE)
class TestModelAdmin(ModelAdmin):
filter_vertical = ["bands"]
self.assertIsInvalid(
TestModelAdmin,
Artist,
"The value of 'filter_vertical[0]' cannot include the ManyToManyField "
"'bands', because that field manually specifies a relationship model.",
"admin.E013",
)
def test_valid_case(self):
class TestModelAdmin(ModelAdmin):
filter_vertical = ("users",)
@ -363,6 +384,26 @@ class FilterHorizontalCheckTests(CheckTestCase):
"admin.E020",
)
@isolate_apps("modeladmin")
def test_invalid_m2m_field_with_through(self):
class Artist(Model):
bands = ManyToManyField("Band", through="BandArtist")
class BandArtist(Model):
artist = ForeignKey("Artist", on_delete=CASCADE)
band = ForeignKey("Band", on_delete=CASCADE)
class TestModelAdmin(ModelAdmin):
filter_horizontal = ["bands"]
self.assertIsInvalid(
TestModelAdmin,
Artist,
"The value of 'filter_horizontal[0]' cannot include the ManyToManyField "
"'bands', because that field manually specifies a relationship model.",
"admin.E013",
)
def test_valid_case(self):
class TestModelAdmin(ModelAdmin):
filter_horizontal = ("users",)