Opened 3 months ago

Closed 2 days ago

Last modified 2 days ago

#36984 closed Cleanup/optimization (fixed)

Prevent extremely long validation messages in inlines

Reported by: Karolis Ryselis Owned by: Karolis Ryselis
Component: contrib.admin Version: 6.0
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Currently Django inlines generate a DeleteProtectedModelForm with hand_clean_DELETE that validates for protected items. If the amount of protected items is large, the error message is huge as all protected objects are listed. The message spanning thousands of entries is impossible to read as is not structured, and nobody is going to check thousands of items manually either. An image showing what it looks like (excuse my locale of the message): https://ibb.co/4RKCK5Nb

Therefore, I propose to limit the amount of protected items shown in inline validation, listing at most N items where N is subject to a discussion, and then adding "and X more" to indicate that the list is not extensive.

Here is a rough idea on how this could be implemented:

def hand_clean_DELETE(self):
    """
    We don't validate the 'DELETE' field itself because on
    templates it's not rendered using the field information, but
    just using a generic "deletion_field" of the InlineModelAdmin.
    """
    if self.cleaned_data.get(DELETION_FIELD_NAME, False):
        using = router.db_for_write(self._meta.model)
        collector = NestedObjects(using=using)
        if self.instance._state.adding:
            return
        collector.collect([self.instance])
        if collector.protected:
            objs = []
            for p in collector.protected[:MAX_VALIDATION_OUTPUT_ITEMS]:
                objs.append(
                    # Translators: Model verbose name and instance
                    # representation, suitable to be an item in a
                    # list.
                    _("%(class_name)s %(instance)s")
                    % {"class_name": p._meta.verbose_name, "instance": p}
                )
            params = {
                "class_name": self._meta.model._meta.verbose_name,
                "instance": self.instance,
            }
            if len(collector.protected) > MAX_VALIDATION_OUTPUT_ITEMS:
                params['related_objects'] = get_text_list(objs, _(", ")) + _(' and %d more') % (len(collector.protected) - MAX_VALIDATION_OUTPUT_ITEMS)
            else:
                params['related_objects'] = get_text_list(objs, _(" and "))
            msg = _(
                "Deleting %(class_name)s %(instance)s would require "
                "deleting the following protected related objects: "
                "%(related_objects)s"
            )
            raise ValidationError(
                msg, code="deleting_protected", params=params
            )

If everyone is happy about this, I could implement the change.

Change History (7)

comment:1 by Jacob Walls, 3 months ago

Owner: set to Karolis Ryselis
Status: newassigned
Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

Thanks, this is similar in spirit to #10919. Thanks for offering a PR as well.

comment:2 by Karolis Ryselis, 3 months ago

Has patch: set

comment:3 by Karolis Ryselis, 3 months ago

I have created a pull request: https://github.com/django/django/pull/20945

comment:4 by Jacob Walls, 7 weeks ago

Patch needs improvement: set

comment:5 by Jacob Walls, 2 days ago

Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

Plan to backport to 6.1, as once we decided to consolidate with the approach in #10919, we realized it was already suggested in the documentation that this worked for inlines as well. So instead of editing the docs for 6.1, and moving the cheese in 6.2, we can just implement the missing feature and ship something more complete.

comment:6 by Jacob Walls <jacobtylerwalls@…>, 2 days ago

Resolution: fixed
Status: assignedclosed

In 57c8c8b1:

Fixed #36984 -- Made inline formset error messages respect delete_confirmation_max_display.

comment:7 by Jacob Walls <jacobtylerwalls@…>, 2 days ago

In 16093e38:

[6.1.x] Fixed #36984 -- Made inline formset error messages respect delete_confirmation_max_display.

Backport of 57c8c8b107248a3358dd26276ac497c577454011 from main.

Note: See TracTickets for help on using tickets.
Back to Top