mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #30231 -- Fixed admin filter horizontal/vertical verbose_name generation.
Co-authored-by: David Smith <smithdc@gmail.com>
This commit is contained in:
parent
06e5f7ae16
commit
45bef6706a
@ -218,12 +218,10 @@
|
||||
// instantiate a new SelectFilter instance for it.
|
||||
if (typeof SelectFilter !== 'undefined') {
|
||||
$('.selectfilter').each(function(index, value) {
|
||||
const namearr = value.name.split('-');
|
||||
SelectFilter.init(value.id, namearr[namearr.length - 1], false);
|
||||
SelectFilter.init(value.id, this.dataset.fieldName, false);
|
||||
});
|
||||
$('.selectfilterstacked').each(function(index, value) {
|
||||
const namearr = value.name.split('-');
|
||||
SelectFilter.init(value.id, namearr[namearr.length - 1], true);
|
||||
SelectFilter.init(value.id, this.dataset.fieldName, true);
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -283,12 +281,10 @@
|
||||
// If any SelectFilter widgets were added, instantiate a new instance.
|
||||
if (typeof SelectFilter !== "undefined") {
|
||||
$(".selectfilter").each(function(index, value) {
|
||||
const namearr = value.name.split('-');
|
||||
SelectFilter.init(value.id, namearr[namearr.length - 1], false);
|
||||
SelectFilter.init(value.id, this.dataset.fieldName, false);
|
||||
});
|
||||
$(".selectfilterstacked").each(function(index, value) {
|
||||
const namearr = value.name.split('-');
|
||||
SelectFilter.init(value.id, namearr[namearr.length - 1], true);
|
||||
SelectFilter.init(value.id, this.dataset.fieldName, true);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -5,9 +5,10 @@ from django.db import models
|
||||
|
||||
from .models import (
|
||||
Author, BinaryTree, CapoFamiglia, Chapter, Child, ChildModel1, ChildModel2,
|
||||
Consigliere, EditablePKBook, ExtraTerrestrial, Fashionista, FootNote,
|
||||
Holder, Holder2, Holder3, Holder4, Holder5, Inner, Inner2, Inner3,
|
||||
Inner4Stacked, Inner4Tabular, Inner5Stacked, Inner5Tabular, NonAutoPKBook,
|
||||
Class, Consigliere, Course, CourseProxy, CourseProxy1, CourseProxy2,
|
||||
EditablePKBook, ExtraTerrestrial, Fashionista, FootNote, Holder, Holder2,
|
||||
Holder3, Holder4, Holder5, Inner, Inner2, Inner3, Inner4Stacked,
|
||||
Inner4Tabular, Inner5Stacked, Inner5Tabular, NonAutoPKBook,
|
||||
NonAutoPKBookChild, Novel, NovelReadonlyChapter, OutfitItem,
|
||||
ParentModelWithCustomPk, Person, Poll, Profile, ProfileCollection,
|
||||
Question, ReadOnlyInline, ShoppingWeakness, Sighting, SomeChildModel,
|
||||
@ -300,6 +301,47 @@ class FashonistaStackedInline(admin.StackedInline):
|
||||
model = Fashionista
|
||||
|
||||
|
||||
# Admin for #30231
|
||||
class ClassStackedHorizontal(admin.StackedInline):
|
||||
model = Class
|
||||
extra = 1
|
||||
filter_horizontal = ['person']
|
||||
|
||||
|
||||
class ClassAdminStackedHorizontal(admin.ModelAdmin):
|
||||
inlines = [ClassStackedHorizontal]
|
||||
|
||||
|
||||
class ClassTabularHorizontal(admin.TabularInline):
|
||||
model = Class
|
||||
extra = 1
|
||||
filter_horizontal = ['person']
|
||||
|
||||
|
||||
class ClassAdminTabularHorizontal(admin.ModelAdmin):
|
||||
inlines = [ClassTabularHorizontal]
|
||||
|
||||
|
||||
class ClassTabularVertical(admin.TabularInline):
|
||||
model = Class
|
||||
extra = 1
|
||||
filter_vertical = ['person']
|
||||
|
||||
|
||||
class ClassAdminTabularVertical(admin.ModelAdmin):
|
||||
inlines = [ClassTabularVertical]
|
||||
|
||||
|
||||
class ClassStackedVertical(admin.StackedInline):
|
||||
model = Class
|
||||
extra = 1
|
||||
filter_vertical = ['person']
|
||||
|
||||
|
||||
class ClassAdminStackedVertical(admin.ModelAdmin):
|
||||
inlines = [ClassStackedVertical]
|
||||
|
||||
|
||||
site.register(TitleCollection, inlines=[TitleInline])
|
||||
# Test bug #12561 and #12778
|
||||
# only ModelAdmin media
|
||||
@ -327,3 +369,7 @@ site.register(Teacher, TeacherAdmin)
|
||||
site.register(Chapter, inlines=[FootNoteNonEditableInlineCustomForm])
|
||||
site.register(OutfitItem, inlines=[WeaknessInlineCustomForm])
|
||||
site.register(Person, inlines=[AuthorTabularInline, FashonistaStackedInline])
|
||||
site.register(Course, ClassAdminStackedHorizontal)
|
||||
site.register(CourseProxy, ClassAdminStackedVertical)
|
||||
site.register(CourseProxy1, ClassAdminTabularVertical)
|
||||
site.register(CourseProxy2, ClassAdminTabularHorizontal)
|
||||
|
@ -294,6 +294,38 @@ class SomeChildModel(models.Model):
|
||||
parent = models.ForeignKey(SomeParentModel, models.CASCADE)
|
||||
readonly_field = models.CharField(max_length=1)
|
||||
|
||||
|
||||
# Models for #30231
|
||||
class Course(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Class(models.Model):
|
||||
person = models.ManyToManyField(Person, verbose_name='attendant')
|
||||
course = models.ForeignKey(Course, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class CourseProxy(Course):
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
|
||||
class CourseProxy1(Course):
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
|
||||
class CourseProxy2(Course):
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
|
||||
# Other models
|
||||
|
||||
|
||||
|
@ -1356,3 +1356,37 @@ class SeleniumTests(AdminSeleniumTestCase):
|
||||
self.assertEqual(
|
||||
len(self.selenium.find_elements_by_css_selector(tabular_inline_formset_selector)), 1
|
||||
)
|
||||
|
||||
def test_inlines_verbose_name(self):
|
||||
"""
|
||||
The item added by the "Add another XXX" link must use the correct
|
||||
verbose_name in the inline form.
|
||||
"""
|
||||
self.admin_login(username='super', password='secret')
|
||||
# Each combination of horizontal/vertical fiter with stacked/tabular
|
||||
# inlines.
|
||||
tests = [
|
||||
'admin:admin_inlines_course_add',
|
||||
'admin:admin_inlines_courseproxy_add',
|
||||
'admin:admin_inlines_courseproxy1_add',
|
||||
'admin:admin_inlines_courseproxy2_add',
|
||||
]
|
||||
css_selector = '.dynamic-class_set#class_set-%s h2'
|
||||
|
||||
for url_name in tests:
|
||||
with self.subTest(url=url_name):
|
||||
self.selenium.get(self.live_server_url + reverse(url_name))
|
||||
# First inline shows the verbose_name.
|
||||
available, chosen = self.selenium.find_elements_by_css_selector(css_selector % 0)
|
||||
self.assertEqual(available.text, 'AVAILABLE ATTENDANT')
|
||||
self.assertEqual(chosen.text, 'CHOSEN ATTENDANT')
|
||||
# Added inline should also have the correct verbose_name.
|
||||
self.selenium.find_element_by_link_text('Add another Class').click()
|
||||
available, chosen = self.selenium.find_elements_by_css_selector(css_selector % 1)
|
||||
self.assertEqual(available.text, 'AVAILABLE ATTENDANT')
|
||||
self.assertEqual(chosen.text, 'CHOSEN ATTENDANT')
|
||||
# Third inline should also have the correct verbose_name.
|
||||
self.selenium.find_element_by_link_text('Add another Class').click()
|
||||
available, chosen = self.selenium.find_elements_by_css_selector(css_selector % 2)
|
||||
self.assertEqual(available.text, 'AVAILABLE ATTENDANT')
|
||||
self.assertEqual(chosen.text, 'CHOSEN ATTENDANT')
|
||||
|
Loading…
Reference in New Issue
Block a user