Opened 8 weeks ago
Last modified 6 weeks ago
#36498 assigned Cleanup/optimization
Inline button to add first / only related instance should say "Add ...", not "Add another ..."
Reported by: | Denis Washington | Owned by: | Dorian Adams |
---|---|---|---|
Component: | contrib.admin | Version: | 5.2 |
Severity: | Normal | Keywords: | inline |
Cc: | Antoliny | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | yes | UI/UX: | yes |
Description
In the default InlineModelAdmin
templates, the button to add a related model instance always says "Add another X", even when
- there is no other related instance (e.g., if
extra=0
or the last related instance was deleted) - if it's not even possible to add multiple related instances (e.g.,
OneToOneField
)
In these cases, I would expect the button to say "Add X" (without "another") instead.
Change History (8)
comment:1 by , 8 weeks ago
Triage Stage: | Unreviewed → Accepted |
---|---|
Type: | Bug → Cleanup/optimization |
comment:2 by , 8 weeks ago
Cc: | added |
---|
comment:3 by , 8 weeks ago
Owner: | set to |
---|---|
Status: | new → assigned |
follow-up: 5 comment:4 by , 7 weeks ago
Should the "add" label be based on the actual database contents or on the user’s visible context? Specifically, when a user has add permission but lacks change permission on an inline model, existing instances may exist but won't be visible to the user.
follow-up: 7 comment:5 by , 7 weeks ago
Replying to Dorian Adams:
Should the "add" label be based on the actual database contents or on the user’s visible context? Specifically, when a user has add permission but lacks change permission on an inline model, existing instances may exist but won't be visible to the user.
(Is it ok to pose this question here)
I believe it should be possible to base it on the actual database contents without requiring additional queries! (Of course, I could be wrong.)
In the Django admin inline, the text for adding an inline form is determined by the inline_formset_data method of the InlineAdminFormSet class.
And if you look at the __iter__
magic method, you'll see that the query is already executed there.(To populate the objects linked to the InlineForm)
so I think we can simply reuse the result of that query like this...
-
django/contrib/admin/helpers.py
diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index 969167f0e2..8586c20a1f 100644
a b class InlineAdminFormSet: 419 419 420 420 def inline_formset_data(self): 421 421 verbose_name = self.opts.verbose_name 422 has_object = any(inlineadminform.original is not None for inlineadminform in self) 422 423 return json.dumps( 423 424 { 424 425 "name": "#%s" % self.formset.prefix,
comment:7 by , 6 weeks ago
Replying to Antoliny:
Thanks for the additional info. It looks like a DB query may be necessary, but only when the user has add permission and lacks change permission. From what I can gather, this is due to the permission-based filtering applied to formset.get_queryset()
within the __iter__
method of InlineAdminFormSet
.
From InlineModelAdmin
:
def get_queryset(self, request): queryset = super().get_queryset(request) if not self.has_view_or_change_permission(request): queryset = queryset.none() return queryset
I opened a PR with a potential workaround that relies on what's available in the database across all scenarios. The query only runs when necessary. However, the potential downside is that this would reveal the existence of records (without exposing their details) to users without view permission.
comment:8 by , 6 weeks ago
Patch needs improvement: | set |
---|
I agree with this proposal as well.
When
extra=0
is set and there are no related objects connected via Inline, I feel that the button to add an InlineForm should say "Add {model_name}", as that is the more appropriate expression.As you mentioned, this is especially true in cases like a
OneToOneField
, where only a single object can be added.