Django admin: переопределить метод удаления

у меня есть admin.py следующим образом:

  class profilesAdmin(admin.ModelAdmin):
     list_display = ["type","username","domain_name"]

теперь я хочу, чтобы выполнить некоторые действия перед удалением объекта:

  class profilesAdmin(admin.ModelAdmin):
     list_display = ["type","username","domain_name"]

     @receiver(pre_delete, sender=profile)
     def _profile_delete(sender, instance, **kwargs):
        filename=object.profile_name+".xml"
        os.remove(os.path.join(object.type,filename))

если я использую метод удаления сигнала, как это я получаю сообщение об ошибке, говорящее self должен быть первым параметром.

как я могу изменить эту функцию?
И я хочу получить profile_name удаляемого объекта. Как это сделать?

Я также попытался переопределить delete_model метод:

def delete_model(self, request, object):
    filename=object.profile_name+".xml"
    os.remove(os.path.join(object.type,filename))
    object.delete()

но это dosn не работает, если несколько объектов должны быть удалены с одного выстрела.

4 ответов


ты на правильном пути с вашим delete_model метод. Когда администратор django выполняет действие сразу на нескольких объектах, он использует функция обновления. Однако, как видно из документов, эти действия выполняются на уровне базы данных только с помощью SQL.

вы должны добавить delete_model метод в качестве настраиваемое действие в Администраторе django.

def delete_model(modeladmin, request, queryset):
    for obj in queryset:
        filename=obj.profile_name+".xml"
        os.remove(os.path.join(obj.type,filename))
        obj.delete()

затем добавьте свою функцию в modeladmin -

class profilesAdmin(admin.ModelAdmin):
    list_display = ["type","username","domain_name"]
    actions = [delete_model]

основная проблема заключается в том, что массовое удаление администратора Django использует SQL, а не экземпляр.исключить (), как отмечалось выше. Для решения только для администратора следующее решение сохраняет интерстициальное "вы действительно хотите удалить их" администратора Django.

наиболее общим решением является переопределение набора запросов, возвращаемого менеджером модели для перехвата delete.

from django.contrib.admin.actions import delete_selected

class BulkDeleteMixin(object):
    class SafeDeleteQuerysetWrapper(object):
        def __init__(self, wrapped_queryset):
            self.wrapped_queryset = wrapped_queryset

        def _safe_delete(self):
            for obj in self.wrapped_queryset:
                obj.delete()

        def __getattr__(self, attr):
            if attr == 'delete':
                return self._safe_delete
            else:
                return getattr(self.wrapped_queryset, attr)

        def __iter__(self):
            for obj in self.wrapped_queryset:
                yield obj

        def __getitem__(self, index):
            return self.wrapped_queryset[index]

        def __len__(self):
            return len(self.wrapped_queryset)

    def get_actions(self, request):
        actions = super(BulkDeleteMixin, self).get_actions(request)
        actions['delete_selected'] = (BulkDeleteMixin.action_safe_bulk_delete, 'delete_selected', ugettext_lazy("Delete selected %(verbose_name_plural)s"))
        return actions

    def action_safe_bulk_delete(self, request, queryset):
        wrapped_queryset = BulkDeleteMixin.SafeDeleteQuerysetWrapper(queryset)
        return delete_selected(self, request, wrapped_queryset)

class SomeAdmin(BulkDeleteMixin, admin.ModelAdmin):
    ...

вы пытаетесь переопределить метод delete_model не удалось, потому что при удалении нескольких объектов django использовать QuerySet.delete(),по соображениям эффективности метод не будет вызван.

вы можете увидеть его там https://docs.djangoproject.com/en/1.9/ref/contrib/admin/actions/
Смотрите начало предупреждения

Admin delete_model() такое же как модель delete() https://github.com/django/django/blob/master/django/contrib/admin/options.py#L1005

поэтому при удалении нескольких объектов пользовательский метод delete никогда не будет вызываться.

у вас есть два пути.

1.пользовательское действие удаления.
модель вызова действия.Удалить() для каждого из выбранных элементов.

2.используйте сигнал.
вы можете использовать только сигнал, а не внутри класса.

вы также можете посмотреть этот вопрос модель Django: delete () не запускается


ваш метод должен быть

class profilesAdmin(admin.ModelAdmin):
    #...

    def _profile_delete(self, sender, instance, **kwargs):
        # do something

    def delete_model(self, request, object):
        # do something

вы должны добавить ссылку на текущий объект в качестве первого аргумента в каждой сигнатуре метода (обычно называемой self). Кроме того, delete_model должен быть реализован как метод.