Django 管理员不处理 ProtectedError 异常
Django admin not handling ProtectedError exception
我有一个 Django 应用程序,它有一个像这样的模型:
class Foo(models.Model):
name = models.CharField(max_length=100)
我在这个模型中有一个特定实例,它的名称是 'bar'(例如),我想防止这个实例被删除。
我创建了一个这样的信号接收器:
def protect_foo_bar(sender, instance, using, **kwargs):
if instance.title != 'bar':
pass
else:
raise ProtectedError(protected_objects=instance, msg='You cannot delete this object')
并且我已将此接收器连接到 pre_delete
信号,如下所示:
pre_delete.connect(receiver=protect_foo_bar, dispatch_uid='protect_foo_bar_signal',
sender='app_name.foo')
当我尝试从 Django 的管理面板中删除这个特定对象时,它 returns 出现异常(错误 500)。是否可以强制管理面板显示 you cannot delete this object
之类的错误而不向用户返回异常?
编辑:
这是回溯:
Traceback:
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\core\handlers\exception.py" in inner
41. response = get_response(request)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\core\handlers\base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\core\handlers\base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\options.py" in wrapper
551. return self.admin_site.admin_view(view)(*args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\utils\decorators.py" in _wrapped_view
149. response = view_func(request, *args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
57. response = view_func(request, *args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\sites.py" in inner
224. return view(request, *args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\utils\decorators.py" in _wrapper
67. return bound_func(*args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\utils\decorators.py" in _wrapped_view
149. response = view_func(request, *args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\utils\decorators.py" in bound_func
63. return func.__get__(self, type(self))(*args2, **kwargs2)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\options.py" in changelist_view
1584. response = self.response_action(request, queryset=cl.get_queryset(request))
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\options.py" in response_action
1286. response = func(self, request, queryset)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\actions.py" in delete_selected
49. queryset.delete()
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\db\models\query.py" in delete
614. deleted, _rows_count = collector.delete()
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\db\models\deletion.py" in delete
279. sender=model, instance=obj, using=self.using
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\dispatch\dispatcher.py" in send
193. for receiver in self._live_receivers(sender)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\dispatch\dispatcher.py" in <listcomp>
193. for receiver in self._live_receivers(sender)
File "C:/Users/asus/PycharmProjects/AleTaha\content\signals.py" in protect_content_category
8. raise ProtectedError(protected_objects=instance, msg='دستهی «همه» را نمیتوان حذف کرد.')
Exception Type: ProtectedError at /admin/content/contentcategory/
Exception Value: ('دسته\u200cی «همه» را نمی\u200cتوان حذف کرد.', <ContentCategory: همه>)
是的,您可以覆盖 ModelAdmin
的 delete_view()
和 response_action()
方法。我还建议重写 has_delete_permission()
方法,这样 "Delete" 按钮就不会出现了:
class MyModelAdmin(admin.ModelAdmin):
def delete_view(self, request, object_id, extra_context=None):
try:
return super().delete_view(request, object_id, extra_context)
except ProtectedError:
msg = "you cannot delete this object"
self.message_user(request, msg, messages.ERROR)
opts = self.model._meta
return_url = reverse(
'admin:%s_%s_change' % (opts.app_label, opts.model_name),
args=(object_id,),
current_app=self.admin_site.name,
)
return HttpResponseRedirect(return_url)
def response_action(self, request, queryset):
try:
return super().response_action(request, queryset)
except ProtectedError:
msg = "you cannot delete this object"
self.message_user(request, msg, messages.ERROR)
opts = self.model._meta
return_url = reverse(
'admin:%s_%s_changelist' % (opts.app_label, opts.model_name),
current_app=self.admin_site.name,
)
return HttpResponseRedirect(return_url)
def has_delete_permission(self, request, obj=None)
return super().has_delete_permission(request, obj) and (
not obj or obj.name != 'bar'
)
我有一个 Django 应用程序,它有一个像这样的模型:
class Foo(models.Model):
name = models.CharField(max_length=100)
我在这个模型中有一个特定实例,它的名称是 'bar'(例如),我想防止这个实例被删除。
我创建了一个这样的信号接收器:
def protect_foo_bar(sender, instance, using, **kwargs):
if instance.title != 'bar':
pass
else:
raise ProtectedError(protected_objects=instance, msg='You cannot delete this object')
并且我已将此接收器连接到 pre_delete
信号,如下所示:
pre_delete.connect(receiver=protect_foo_bar, dispatch_uid='protect_foo_bar_signal',
sender='app_name.foo')
当我尝试从 Django 的管理面板中删除这个特定对象时,它 returns 出现异常(错误 500)。是否可以强制管理面板显示 you cannot delete this object
之类的错误而不向用户返回异常?
编辑:
这是回溯:
Traceback:
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\core\handlers\exception.py" in inner
41. response = get_response(request)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\core\handlers\base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\core\handlers\base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\options.py" in wrapper
551. return self.admin_site.admin_view(view)(*args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\utils\decorators.py" in _wrapped_view
149. response = view_func(request, *args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
57. response = view_func(request, *args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\sites.py" in inner
224. return view(request, *args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\utils\decorators.py" in _wrapper
67. return bound_func(*args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\utils\decorators.py" in _wrapped_view
149. response = view_func(request, *args, **kwargs)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\utils\decorators.py" in bound_func
63. return func.__get__(self, type(self))(*args2, **kwargs2)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\options.py" in changelist_view
1584. response = self.response_action(request, queryset=cl.get_queryset(request))
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\options.py" in response_action
1286. response = func(self, request, queryset)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\contrib\admin\actions.py" in delete_selected
49. queryset.delete()
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\db\models\query.py" in delete
614. deleted, _rows_count = collector.delete()
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\db\models\deletion.py" in delete
279. sender=model, instance=obj, using=self.using
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\dispatch\dispatcher.py" in send
193. for receiver in self._live_receivers(sender)
File "C:\Users\asus\PycharmProjects\AleTaha\env\lib\site-packages\django\dispatch\dispatcher.py" in <listcomp>
193. for receiver in self._live_receivers(sender)
File "C:/Users/asus/PycharmProjects/AleTaha\content\signals.py" in protect_content_category
8. raise ProtectedError(protected_objects=instance, msg='دستهی «همه» را نمیتوان حذف کرد.')
Exception Type: ProtectedError at /admin/content/contentcategory/
Exception Value: ('دسته\u200cی «همه» را نمی\u200cتوان حذف کرد.', <ContentCategory: همه>)
是的,您可以覆盖 ModelAdmin
的 delete_view()
和 response_action()
方法。我还建议重写 has_delete_permission()
方法,这样 "Delete" 按钮就不会出现了:
class MyModelAdmin(admin.ModelAdmin):
def delete_view(self, request, object_id, extra_context=None):
try:
return super().delete_view(request, object_id, extra_context)
except ProtectedError:
msg = "you cannot delete this object"
self.message_user(request, msg, messages.ERROR)
opts = self.model._meta
return_url = reverse(
'admin:%s_%s_change' % (opts.app_label, opts.model_name),
args=(object_id,),
current_app=self.admin_site.name,
)
return HttpResponseRedirect(return_url)
def response_action(self, request, queryset):
try:
return super().response_action(request, queryset)
except ProtectedError:
msg = "you cannot delete this object"
self.message_user(request, msg, messages.ERROR)
opts = self.model._meta
return_url = reverse(
'admin:%s_%s_changelist' % (opts.app_label, opts.model_name),
current_app=self.admin_site.name,
)
return HttpResponseRedirect(return_url)
def has_delete_permission(self, request, obj=None)
return super().has_delete_permission(request, obj) and (
not obj or obj.name != 'bar'
)