Opened 16 years ago

Last modified 12 months ago

#10919 new New feature

Add an option to disable display of related items on admin's delete confirmation page (to prevent large memory usage on complex objects)

Reported by: Tobias McNulty Owned by: nobody
Component: contrib.admin Version: dev
Severity: Normal Keywords: admin memory limit
Cc: aaron@…, sasha@…, michal@…, Sergii Lapin Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I recently tried to delete an object in the admin that had several million related objects.

The server quickly ran out of memory as the apache process's memory usage ballooned upwards to near a gigabyte.

I assume this is because it was trying to create an HTML page listing out all the related objects.

Can the admin page do a count and/or limit to avoid this?

I'm using Django 1.1 trunk (r10628), mod_wsgi 2.0, and apache 2.2.8.

Change History (13)

comment:1 by Alex Gaynor, 15 years ago

Triage Stage: UnreviewedAccepted

comment:2 by Luke Plant, 14 years ago

Severity: Normal
Type: Bug

comment:3 by anonymous, 13 years ago

Easy pickings: unset
UI/UX: unset

This bug is still sitting around. Maybe we should document it somewhere, that for complex objects...

comment:4 by Tim Graham, 9 years ago

Summary: admin object deletion confirmation page causes server out of memory errorAdd an option to disable display of related items on admin's delete confirmation page (to prevent large memory usage on complex objects)
Type: BugNew feature
Version: 1.1-betamaster

An option to disable or limit the display of related objects on the delete confirmation page seems like a workable solution here (other ideas welcome).

comment:5 by Aaron C. de Bruyn, 9 years ago

Cc: aaron@… added

comment:6 by Sasha Gaevsky, 9 years ago

Cc: sasha@… added

A property for ModelAdmin ?

comment:7 by Michal Čihař, 9 years ago

Adding such property to ModelAdmin sounds like a good idea.

I've workarounded it myself by removing deleted_objects before rendering the template:

    def render_delete_form(self, request, context):
        context['deleted_objects'] = [_('Object listing disabled')]
        return super(ProjectAdmin, self).render_delete_form(request, context)

This way I will get the summary (so that user has idea what he is deleting), but not object list as it is too long to get displayed.

comment:8 by Michal Čihař, 9 years ago

Cc: michal@… added

comment:9 by Sergii Lapin, 6 years ago

Actually, removing deleted_objects from context doesn't prevent from collecting related items by django.contrib.admin.utils.NestedObjects in django.contrib.admin.utils.get_deleted_objects
Maybe it better off to override get_deleted_objects function (Django 2.1+ has this method inside AdminModel class). But there appears new issue: How to check permissions and protected foreign keys for related items?..

Last edited 6 years ago by Sergii Lapin (previous) (diff)

comment:10 by Sergii Lapin, 6 years ago

Cc: Sergii Lapin added

in reply to:  description comment:11 by Sivakumar R, 5 years ago

Replying to Tobias McNulty:

I recently tried to delete an object in the admin that had several million related objects.

The server quickly ran out of memory as the apache process's memory usage ballooned upwards to near a gigabyte.

I assume this is because it was trying to create an HTML page listing out all the related objects.

Can the admin page do a count and/or limit to avoid this?

I'm using Django 1.1 trunk (r10628), mod_wsgi 2.0, and apache 2.2.8.

I tried one method. I don't want related objects. So i overrided the get_deleted_object() method. But i removed "to_delete = collector.nested(format_callback)" line and return just the queryset(objs). So it will show only the objects to delete. Is there any issue with this method? If there any, please tell me.

in reply to:  9 comment:12 by Sivakumar R, 5 years ago

Replying to Tobias McNulty:

I recently tried to delete an object in the admin that had several million related objects.

The server quickly ran out of memory as the apache process's memory usage ballooned upwards to near a gigabyte.

I assume this is because it was trying to create an HTML page listing out all the related objects.

Can the admin page do a count and/or limit to avoid this?

I'm using Django 1.1 trunk (r10628), mod_wsgi 2.0, and apache 2.2.8.

I tried one method. I don't want related objects. So i overrided the get_deleted_object() method. But i removed "to_delete = collector.nested(format_callback)" line and return just the queryset(objs). So it will show only the objects to delete. Is there any issue with this method? If there any, please tell me. I am using djang 1.11.

Last edited 5 years ago by Sivakumar R (previous) (diff)

comment:13 by terminator14, 5 years ago

I am using Django 2.2.10, and this is still an issue.
If I am using Django Admin to delete an object with millions of related records, it tries to generate the list, takes too long, and my browser gives up waiting, showing an error loading the page.

I'm not sure how difficult this is to do, but I have some thoughts:

When deleting an object from Django Admin, the summary section is great, but I really like the fact that Django Admin lists all effected related objects. If the summary section was the only thing on the page, someone deleting an object may think "pfft - I know exactly what happens if I delete this", and delete it without a second thought, without even bothering to glance at the summary of the number of related objects that will be effected. I know this sounds like a "that's their problem" type of deal, but if we can prevent this, why wouldn't we?

The list of effected objects that Django Admin currently provides is very clear. As soon as the page loads, if you think you are about to delete one object, but you see a massive list of effected stuff, you immediately start looking into what you are deleting, and why it effects more than what you expected.

I think a good solution would be a middle-ground, rather than disabling the list of related objects.

If you are about to delete an object with a million related objects, have django do a DB query with something like "limit 100". It will pull 100 related objects, quickly generate the HTML page without trying to list a million objects on the page, and the user will still have the advantage of quickly seeing that his delete operation will effect a ton of objects, since he'll have a hundred objects listed on the page.

To make things clear, add a message at the bottom that says something like "and 999,900 others" or something. This will tell them that the 100 objects listed aren't the only ones to be deleted.

This strategy could just be enabled all the time, rather than having an option to disable the listing of related objects on the delete page berried in ModelAdmin somewhere, since there's NEVER a need to try to actually list all 1,000,000 related objects in an HTML page.

Any thoughts?

Update:

This would fix taking too long to load the delete_selected_confirmation.html and delete_confirmation.html templates, but does NOT address the actual deletion operation.
From what I understand, deleting an object with a million references has 2 main issues:

  • Loading the confirmation templates (which I try to address above)
  • The actual deletion database operation, which happens after the confirmation

The actual deletion operation from the database can also take a while. If you have enough related objects, and the operation takes long enough, the browser may also stop waiting for a response and show an error. This would also be nice to address, but would likely be a far more difficult problem. The deletion would need to be an asynchronous operation which would mark the object as deleted (or hidden) so that Django Admin no longer shows it to logged in users, but it would have to run in the background until it is complete. Or perhaps instead of running in the background, it can tell the database to delete those related objects, and return without waiting to find out of the database succeeded? Just spitballing here. The solution may need to consider things like:

  • Being compatible with WSGI, which may be using processes, threads, or one of several async libraries
  • Being compatible with Django channels, which also probably impacts how background tasks run
  • The new Django 3 async efforts
Last edited 5 years ago by terminator14 (previous) (diff)
Note: See TracTickets for help on using tickets.
Back to Top