【问题标题】:Catch exception on save in Django admin?在 Django 管理员中保存时捕获异常?
【发布时间】:2014-12-20 15:42:40
【问题描述】:

我在一堆模型上有一个pre_save 信号处理程序,它们写入不同的数据库。如果出现问题,我想中止整个保存,或者失败时向用户发送消息。

基于Display custom message from signal in the admin,我写了一个mixin,方法如下:

class SafeSaveMixin(object):
    def save_model(self, request, *args, **kwargs):
        try:
            return super(SafeSaveMixin, self).save_model(request, *args, **kwargs)
        except Exception as e:
            self.message_user(request, e, messages.ERROR)

这允许我从pre_save 处理程序中抛出一个异常并将消息显示给用户。问题是,即使最终跳过了实际的 Model.save(),管理控制台也看不到任何内容,因此它仍然报告该对象已成功保存。

如果我将pre_save 处理程序更改为post_save 处理程序,这将允许基础Model.save() 发生,并且至少 Django 会报告正确的状态,但我需要在另一个数据库中的信息是基于对象的 previous 状态,所以我需要在保存之前到达它。

我还考虑将错误消息填充到 pre_save 中的对象本身中,并将其从 mixin 的 save_model() 中提取出来——但这在其他 ModelAdmin 保存方法中变得更加复杂,例如 save_formset() .

有什么好的方法吗?

【问题讨论】:

标签: django django-admin


【解决方案1】:

我想出了这个,它被混入了 ModelAdmin 类:

class InternalModelAdminMixin:
    """Mixin to catch all errors in the Django Admin and map them to user-visible errors."""
    def change_view(self, request, object_id, form_url='', extra_context=None):
        try:
            return super().change_view(request, object_id, form_url, extra_context)
        except Exception as e:
            self.message_user(request, 'Error changing model: %s' % e.msg, level=logging.ERROR)
            # This logic was cribbed from the `change_view()` handling here:
            # django/contrib/admin/options.py:response_post_save_add()
            # There might be a simpler way to do this, but it seems to do the job.
            return HttpResponseRedirect(request.path)

这不会干扰实际的模型保存过程,只是防止 500 错误重定向。 (请注意,这将禁用调试堆栈跟踪处理。您可以添加一些条件处理以将其重新添加)。

【讨论】:

  • 有什么使用指南吗?
  • @sami 只需将其混入到继承自 ModelAdmin 的类中即可:class MyAdmin(InternalModelAdminMixin, ModelAdmin):
【解决方案2】:

捕获此类错误是不可取的。这可能意味着您向用户公开敏感信息,例如关于数据库(如果有 IntegrityError)。由于这绕过了正常的错误处理,您可能还会错过通知您错误的消息。

如果需要对用户输入的错误/不完整数据进行一些检查,那么可以在def clean(self) 中执行此操作

def clean(self):
    cleaned_data = super(ContactForm, self).clean()
    field_value = cleaned_data.get('field_name')
    if not field_value:
        raise ValidationError('No value for field_name')

【讨论】:

  • 我不同意你的笼统说法“不应该是可取的”。抛出 500 错误的默认错误处理是糟糕的 UX,对于内部公司仪表板,在我的情况下,最好只显示模型错误的文本。通常这很有帮助,例如“无法添加模型 x,因为 ”,管理员可以对其采取行动。肯定有很多情况下您不想暴露这样的模型错误,例如如果您有很多用户,或者 django 管理员的非内部用户。
猜你喜欢
  • 2012-12-24
  • 2021-08-03
  • 2018-08-25
  • 2019-07-09
  • 1970-01-01
  • 2015-12-17
  • 2012-06-09
  • 1970-01-01
  • 2023-03-26
相关资源
最近更新 更多