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
должен быть первым параметром.
Как изменить приведенную выше функцию?
И я хочу получить имя_файла удаляемого объекта. Как это можно сделать?
Я также попытался переопределить метод delete_model:
def delete_model(self, request, object):
filename=object.profile_name+".xml"
os.remove(os.path.join(object.type,filename))
object.delete()
Но это не работает, если несколько объектов должны быть удалены одним выстрелом.
Ответы
Ответ 1
Вы на правильном пути с вашим методом 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]
Ответ 2
Основная проблема заключается в том, что в Django для массового удаления используется SQL, а не instance.delete(), как указано в другом месте. Для решения, предназначенного только для администратора, следующее решение сохраняет администратор Django "вы действительно хотите удалить эти" межстраничные.
Самое общее решение - переопределить запрос, возвращенный диспетчером модели, для перехвата удаления.
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):
...
Ответ 3
вы пытаетесь переопределить метод delete_model, потому что, когда вы удаляете несколько объектов, django использует QuerySet.delete()
, по соображениям эффективности ваш метод 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
поэтому при удалении нескольких объектов пользовательский метод удаления никогда не будет вызываться.
у вас есть два пути.
1.Удалить действие удаления.
действие вызывает Model.delete() для каждого из выбранных элементов.
сигнал 2.use.
вы можете использовать сигнал самостоятельно, а не внутри класса.
вы также можете посмотреть этот вопрос модель Django: delete() не запускается
Ответ 4
Ваш метод должен быть
class profilesAdmin(admin.ModelAdmin):
#...
def _profile_delete(self, sender, instance, **kwargs):
# do something
def delete_model(self, request, object):
# do something
Вы должны добавить ссылку на текущий объект в качестве первого аргумента в каждой сигнатуре метода (обычно называемой self
). Кроме того, delete_model должен быть реализован как метод.
Ответ 5
Вы можете использовать delete_queryset из Django 2.1 и выше для массового удаления объектов и delete_model для одиночного удаления. Оба метода будут обрабатывать что-то перед удалением объекта.
ModelAdmin.delete_queryset (запрос, набор запросов)
Это объяснение delete_queryset в примечании к выпуску Django 2.1.
Метод delete_queryset() получает HttpRequest и QuerySet объектов, которые необходимо удалить. Переопределите этот метод, чтобы настроить процесс удаления для "удаления выбранных объектов"
Давайте посмотрим, что делает delete_queryset, вы можете переопределить admin. Класс ModelAdmin таким образом, включая функцию delete_queryset. Здесь вы получите список объектов, а queryset.delete()
означает удаление всех объектов одновременно, или вы можете добавить цикл для удаления один за другим.
def delete_queryset(self, request, queryset):
print('==========================delete_queryset==========================')
print(queryset)
"""
you can do anything here BEFORE deleting the object(s)
"""
queryset.delete()
"""
you can do anything here AFTER deleting the object(s)
"""
print('==========================delete_queryset==========================')
Итак, я собираюсь удалить 5 объектов из "окна выбора", и вот эти 5 объектов.
![deleting 5 objects from "select window"]()
Затем вы будете перенаправлены на страницу подтверждения, как это,
![going to delete those 5 objects]()
Помните о кнопке "Да, я уверен", и я объясню это позже. Когда вы нажмете эту кнопку, вы увидите изображение ниже после удаления этих 5 объектов.
![successfully deleted 5 objects]()
Это вывод терминала,
![terminal output of those 5 objects]()
Таким образом, вы получите эти 5 объектов в виде списка QuerySet, и перед удалением вы можете делать все что угодно в области комментариев.
ModelAdmin.delete_model (запрос, объект)
Это объяснение о delete_model.
Метод delete_model получает HttpRequest и экземпляр модели. Переопределение этого метода позволяет выполнять pre- или операции после удаления. Вызовите super(). Delete_model(), чтобы удалить объект с помощью Model.delete().
Давайте посмотрим, что делает delete_model, вы можете переопределить admin. Класс ModelAdmin таким образом, включая функцию delete_model.
actions = ['delete_model']
def delete_model(self, request, obj):
print('============================delete_model============================')
print(obj)
"""
you can do anything here BEFORE deleting the object
"""
obj.delete()
"""
you can do anything here AFTER deleting the object
"""
print('============================delete_model============================')
Я просто щелкаю свой 6-й объект, чтобы удалить его из "окна изменения".
![deleting 1 object from "change window"]()
Есть еще одна кнопка "Удалить", при нажатии на которую вы увидите окно, которое мы видели ранее.
![going to delete those 1 object]()
Нажмите кнопку "Да, я уверен", чтобы удалить один объект. Вы увидите следующее окно с уведомлением об этом удаленном объекте.
![successfully deleted 1 object]()
Это вывод терминала,
![terminal output of those 1 object]()
Таким образом, вы получите выделенный объект как один из QuerySet, и перед удалением вы можете делать все что угодно в области комментариев.
Окончательный вывод: вы можете обработать событие удаления, нажав кнопку "Да, я уверен" в "окне выбора" или "окне изменения" на сайте администратора Django, используя delete_queryset и delete_model. Таким образом, нам не нужно обрабатывать такие сигналы, как django.db.models.signals.pre_delete или django.db.models.signals.post_delete.
Вот полный код,
from django.contrib import admin
from . import models
class AdminInfo(admin.ModelAdmin):
model = models.AdminInfo
actions = ['delete_model']
def delete_queryset(self, request, queryset):
print('========================delete_queryset========================')
print(queryset)
"""
you can do anything here BEFORE deleting the object(s)
"""
queryset.delete()
"""
you can do anything here AFTER deleting the object(s)
"""
print('========================delete_queryset========================')
def delete_model(self, request, obj):
print('==========================delete_model==========================')
print(obj)
"""
you can do anything here BEFORE deleting the object
"""
obj.delete()
"""
you can do anything here AFTER deleting the object
"""
print('==========================delete_model==========================')
admin.site.register(models.AdminInfo, AdminInfo)