makinacorpus / django-safedelete

Mask your objects instead of deleting them from your database.
https://django-safedelete.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
678 stars 122 forks source link

Adding HARD_DELETE action for SOFT_DELETE models in Admin panel #146

Open bernardobgam opened 3 years ago

bernardobgam commented 3 years ago

It would be very helpful to be able to manually HARD DELETE objects in the admin panel which have a SOFT_DELETE or SOFT_DELETE_CASCADE policy.

Thank you for your project!

helena238 commented 3 years ago

Hi! I also needed the hard delete admin action in my project. I have extended the SafeDeleteAdmin class as follows:

from safedelete.admin import SafeDeleteAdmin
from safedelete.models import HARD_DELETE
from safedelete.utils import related_objects

from django.contrib import admin, messages
from django.template.response import TemplateResponse
from django.contrib.admin.utils import model_ngettext
from django.utils.encoding import force_text
from django.core.exceptions import PermissionDenied

class SafeDeleteAdminExtended(SafeDeleteAdmin):

    hard_delete_template = "hard_delete_template.html"
    actions = ['undelete_selected', 'hard_delete', ]

    def hard_delete(self, request, queryset):
        """ Admin action to delete objects finally. """
        if not self.has_delete_permission(request):
            raise PermissionDenied

        original_queryset = queryset.all()
        queryset = queryset.filter(deleted__isnull=False)

        if request.POST.get('post'):
            requested = original_queryset.count()
            changed = queryset.count()

            if changed:
                for obj in queryset:
                    obj.delete(force_policy=HARD_DELETE)
                if requested > changed:
                    self.message_user(
                        request,
                        "Successfully hard deleted %(count_changed)d of the "
                        "%(count_requested)d selected %(items)s." % {
                            "count_requested": requested,
                            "count_changed": changed,
                            "items": model_ngettext(self.opts, requested)
                        },
                        messages.WARNING,
                    )
                else:
                    self.message_user(
                        request,
                        "Successfully hard deleted %(count)d %(items)s." % {
                            "count": changed,
                            "items": model_ngettext(self.opts, requested)
                        },
                        messages.SUCCESS,
                    )
            else:
                self.message_user(
                    request,
                    "No permission for hard delete. Execute soft delete first.",
                    messages.ERROR
                )
            return None

        opts = self.model._meta
        if len(original_queryset) == 1:
            objects_name = force_text(opts.verbose_name)
        else:
            objects_name = force_text(opts.verbose_name_plural)
        title = "Are you sure?"

        deletable_objects, model_count, perms_needed, protected = self.get_deleted_objects(queryset, request)

        context = {
            'title': title,
            'objects_name': objects_name,
            'queryset': queryset,
            'original_queryset': original_queryset,
            'opts': opts,
            'app_label': opts.app_label,
            'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
            'model_count': dict(model_count).items(),
            'deletable_objects': [deletable_objects],
            'perms_lacking': perms_needed,
            'protected': protected,
            'media': self.media,
        }

        return TemplateResponse(
                request,
                self.hard_delete_template,
                context,
            )

    hard_delete.short_description = "Hard delete selected %(verbose_name_plural)s."

If there is interest I can integrate my solution in the existing framework.

bernardobgam commented 3 years ago

@helena238 This would be great!

Gagaro commented 3 years ago

Feel free to open a pull request.

Gagaro commented 3 years ago

Actually this is a duplicate of #88, I'll close the older one.

EBI3827 commented 3 years ago

@helena238 thank you for your great improvement , where should I find hard_delete_template.html? or I myself must create it?