在Django admin中保存时捕获异常?

Ada*_*dam 11 django django-admin

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

基于在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)
Run Code Online (Sandbox Code Playgroud)

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

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

我还考虑将错误消息填充到对象本身pre_save并在mixin 中将其拉出save_model()- 但是在其他ModelAdmin保存方法中这会变得更复杂save_formset().

有什么好办法吗?

Sym*_*ric 5

我想出了这个,它被混合到 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)
Run Code Online (Sandbox Code Playgroud)

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

  • 有关于如何使用它的指南吗? (2认同)

Hus*_*sam 2

捕获此类错误不应该是可取的。这可能意味着您向用户暴露了敏感信息,例如有关数据库的信息(如果存在完整性错误)。由于这会绕过正常的错误处理,因此您可能还会错过通知您错误的消息。

如果需要对用户输入的错误/不完整数据进行一些检查,那么正确的方法是在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')
Run Code Online (Sandbox Code Playgroud)

  • 我不同意你的宽泛说法“不应该是可取的”。抛出 500 错误的默认错误处理是糟糕的用户体验,对于内部公司仪表板,在我的情况下,仅显示模型错误的文本是更好的选择。通常这是一些有用的信息,例如“由于<域原因Y>而无法添加模型x”,管理员可以对此采取行动。在很多情况下,您肯定不希望暴露这样的模型错误,例如,如果您有很多用户或 django 管理员的非内部用户。 (5认同)