#30231 closed Bug (fixed)
Field's verbose_name is ignored in FilteredSelectMultiple widget for inlines created with "Add another" button
Reported by: | Florian Schuler | Owned by: | David Smith |
---|---|---|---|
Component: | contrib.admin | Version: | 2.1 |
Severity: | Normal | Keywords: | |
Cc: | Florian Schuler, Carlton Gibson | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | yes |
Description
When using the FilteredSelectMultiple widget (filter_horizontal) in a TabularInline view on a ModelAdmin page the "verbose_name" of a ManyToManyField is ignored for newly added objects via the "add another" button. It simply displays the field name for those elements. The FilteredSelectMultiple widgets of initially loaded / already existing objects is displayed correctly with the use of the "verbose_name" of the regarding field.
It seems like a small JS Bug, because when checking out the generated HTML source code, the "select"-element has always the correct "data-field-name" attribute which fits to the "verbose_name" (for the newly added objects too). But when the FilteredSelectMultiple widget of newly added objects is initialized the generation of the heading and the help texts seems to ignore this "data-field-name" attribute / the "verbose_name" and instead uses simply the field name.
See attached screenshot for explanation.
Attachments (1)
Change History (23)
by , 6 years ago
Attachment: | screenshot.jpg added |
---|
comment:1 by , 6 years ago
Cc: | added |
---|
comment:2 by , 6 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:4 by , 6 years ago
Hello @Florian Schuler, actually not. It happens in admin.TabularInline view or in the admin modelview once that we have a form with FilteredSelectMultiple?
Thank you
follow-up: 6 comment:5 by , 6 years ago
Easy pickings: | unset |
---|---|
Summary: | "verbose_name" is ignored in FilteredSelectMultiple widget for new objects → Field's verbose_name is ignored in FilteredSelectMultiple widget for inlines created with "Add another" button |
Triage Stage: | Unreviewed → Accepted |
I reproduced at 9681e968ebdcd58cac99c1e60f0a6932abd4e5c9 with this patch on the tutorial:
-
polls/admin.py
diff --git a/polls/admin.py b/polls/admin.py index f1bf573..0a184ab 100644
a b from .models import Choice, Question 6 6 class ChoiceInline(admin.TabularInline): 7 7 model = Choice 8 8 extra = 3 9 filter_horizontal = ['groups'] 9 10 10 11 11 12 class QuestionAdmin(admin.ModelAdmin): -
polls/models.py
diff --git a/polls/models.py b/polls/models.py index 38ae549..b0756e3 100644
a b import datetime 4 4 5 5 from six import python_2_unicode_compatible 6 6 7 from django.contrib.auth.models import Group 7 8 from django.db import models 8 9 from django.utils import timezone 9 10 … … class Choice(models.Model): 29 30 question = models.ForeignKey(Question, on_delete=models.CASCADE) 30 31 choice_text = models.CharField(max_length=200) 31 32 votes = models.IntegerField(default=0) 33 groups = models.ForeignKey(Group, blank=True, verbose_name='test') 32 34 33 35 def __str__(self): 34 36 return self.choice_text
comment:6 by , 6 years ago
Replying to Ahisahar Pretel:
Hello @Florian Schuler, actually not. It happens in admin.TabularInline view or in the admin modelview once that we have a form with FilteredSelectMultiple?
Thank you
Like Tim Graham just confirmed it happens in admin.TabularInline view, when adding a field to "filter_horizontal". In addition I already tried to overwrite get_formset method of the regarding admin.TabularInline and added FilteredSelectMultiple widget manually with verbose_name redefined on the widget instead, but with the same result. So the bug occurs with manually added FilteredSelectMultiple widgets too.
@Tim Graham thank you for the confirmation of the bug and clarifying the title of the ticket! Of course it is important that this only happens to inlines added via the "add another" button.
follow-up: 8 comment:7 by , 6 years ago
I should probably let it to someone who has more experience right @Florian Schuler @Tim Graham? This is my first contribution
comment:8 by , 6 years ago
Replying to Ahisahar Pretel:
I should probably let it to someone who has more experience right @Florian Schuler @Tim Graham? This is my first contribution
Hey @Ahisahar Pretel and @Tim Graham, I just found the origin of this wrong behaviour and fixed it in my local Django system (2.1.7)!
Like already noted in my bug report it seems like a small logic fault in a javascript file. In the file which is responsible for initializing the FilteredSelectMultiple widget at page load (django/contrib/admin/static/admin/js/SelectFilter2.js) there is the correct usage of calling the SelectFilter.init() method at the very end (line 244 to 250):
window.addEventListener('load', function(e) { $('select.selectfilter, select.selectfilterstacked').each(function() { var $el = $(this), data = $el.data(); SelectFilter.init($el.attr('id'), data.fieldName, parseInt(data.isStacked, 10)); }); });
So second parameter has to be the data attribute fieldName of the HTML element, which represents the verbose_name if one is given for the field.
In the js file which is responsible for triggering the initialization of newly added FilteredSelectMultiple Widgets after clicking the "add another" button (django/contrib/admin/static/admin/js/inlines.js) this parameter isn't set correctly.
For tabular inlines:
Current function:
var updateSelectFilter = function() { // If any SelectFilter widgets are a part of the new form, // instantiate a new SelectFilter instance for it. if (typeof SelectFilter !== 'undefined') { $('.selectfilter').each(function(index, value) { var namearr = value.name.split('-'); SelectFilter.init(value.id, namearr[namearr.length - 1], false); }); $('.selectfilterstacked').each(function(index, value) { var namearr = value.name.split('-'); SelectFilter.init(value.id, namearr[namearr.length - 1], true); }); } };
So it gets the field name out of the "name" attribute which is the real field name, not the verbose name which could be easily taken with "$(this).data('fieldName')"
Corrected function should be:
var updateSelectFilter = function() { // If any SelectFilter widgets are a part of the new form, // instantiate a new SelectFilter instance for it. if (typeof SelectFilter !== 'undefined') { $('.selectfilter').each(function(index, value) { SelectFilter.init(value.id, $(this).data('fieldName'), false); }); $('.selectfilterstacked').each(function(index, value) { SelectFilter.init(value.id, $(this).data('fieldName'), true); }); } };
The same for Stacked inline:
Current function:
var updateSelectFilter = function() { // If any SelectFilter widgets were added, instantiate a new instance. if (typeof SelectFilter !== "undefined") { $(".selectfilter").each(function(index, value) { var namearr = value.name.split('-'); SelectFilter.init(value.id, namearr[namearr.length - 1], false); }); $(".selectfilterstacked").each(function(index, value) { var namearr = value.name.split('-'); SelectFilter.init(value.id, namearr[namearr.length - 1], true); }); } };
Corrected function should be:
var updateSelectFilter = function() { // If any SelectFilter widgets were added, instantiate a new instance. if (typeof SelectFilter !== "undefined") { $(".selectfilter").each(function(index, value) { SelectFilter.init(value.id, $(this).data('fieldName'), false); }); $(".selectfilterstacked").each(function(index, value) { SelectFilter.init(value.id, $(this).data('fieldName'), true); }); } };
At least on my side everything is working correctly with these changes.
Maybe one of you could recheck my changes and test it on a clean project if everything is still working like expected and maybe it would also be a good idea to search for more SelectFilter.init() calls at other places in the code?! Don't know if it is anywhere else wrongly used.
It would also be good to check if the data attribute fieldName is guaranteed to be set, but because it is used in this way in the SelectFilter2.js file i would think so... But i still wonder why it was wrongly implemented in the inlines.js file (maybe there was a change someday at the generation of the selectfilter elements and the fieldName attribute was added later and no one thought about changing it in inlines.js file too?!).
@Ahisahar Pretel or @Tim Graham could any of you take care of checking this out and submitting a patch?
comment:9 by , 6 years ago
Owner: | changed from | to
---|
comment:10 by , 6 years ago
Just submitted a patch with the changes i already mentioned above and made a pull request.
https://github.com/django/django/pull/11076
comment:11 by , 6 years ago
Has patch: | set |
---|
follow-up: 13 comment:12 by , 6 years ago
Needs tests: | set |
---|
Tests (probably using selenium in this case) are also required.
comment:13 by , 6 years ago
Replying to Tim Graham:
Tests (probably using selenium in this case) are also required.
Hey Tim, I don't know what tests could be useful in this case of UI bug where only a wrong name was passed to display (it's a very trivial bugfix, simply fetching the name from fieldName attribute instead). I don't have any experience in writing tests using selenium for Django UI and also don't have any time for reading into it and setting up a testing environment at the moment. So if there really should be tests needed, someone else needs to take care of it.
follow-up: 15 comment:14 by , 6 years ago
Owner: | removed |
---|---|
Status: | assigned → new |
Okay, I'll deassign the ticket then. Even trivial bug fixes require tests to prevent regressions.
comment:15 by , 6 years ago
Replying to Tim Graham:
Okay, I'll deassign the ticket then. Even trivial bug fixes require tests to prevent regressions.
Hey Tim, Okay!
Just noticed that the owner field of this ticket is now empty. Shouldn't it be "nobody" like the other new tickets so that other users can query for unassigned tickets by searching for owner "nobody"?
comment:16 by , 6 years ago
Owner: | set to |
---|---|
Status: | new → assigned |
comment:17 by , 6 years ago
Hi! I submitted a new patch with the changes Florian made and the Selenium test
https://github.com/django/django/pull/11282
comment:18 by , 4 years ago
Cc: | added |
---|---|
Needs tests: | unset |
comment:19 by , 4 years ago
Owner: | changed from | to
---|
comment:20 by , 4 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
Screenshot which shows wrong display of field verbose_name