IntegrityError(Django ORM)中缺少表名

gue*_*tli 8 python django postgresql django-orm

我错过了Django的IntegrityError中的表名:

Traceback (most recent call last):
...
    return self.cursor.execute(sql, params)
  File ".../django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File ".../django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
IntegrityError: null value in column "manager_slug" violates not-null constraint
DETAIL:  Failing row contains (17485, null, 2017-10-10 09:32:19, , 306).
Run Code Online (Sandbox Code Playgroud)

有没有办法查看INSERT/UPDATE正在访问哪个表?

我们使用PostgreSQL 9.6.

这是一个通用问题:如何获得更好的错误消息?

这不是关于这个特定专栏的问题.我很快就找到了相关的表格和专栏.但我想改进来自CI系统的错误消息.下次我想立即看到表名.

我知道如果我在软件开发过程中看到此错误,我可以使用调试器轻松地显示缺少的信息.但在我的情况下,这发生在生产中,我只有像上面这样的堆栈跟踪.

hyn*_*cer 6

此回溯中的异常消息是来自数据库驱动程序的原始消息.知道这个和回溯是有用的,如果有任何谷歌搜索,报告等.

异常类与django.db.utils相同.所有后端的IntegrityError,但消息或更确切的参数取决于后端:

  • postgres:null value in column "manager_slug" violates not-null constraint\n DETAILS...\n
  • mysql..:(1048, "Column 'manager_slug' cannot be null")
  • sqlite3.:NOT NULL constraint failed: appname_modelname.manager_slug

表名仅在sqlite3后端可见.一些后端仅使用异常的字符串参数,但mysql使用两个参数:数字错误代码和消息.(我喜欢接受这是一个普遍的问题,不仅仅是PostgreSQL.)一些后端的作者希望应用程序的作者直接或从SQL知道表名,但对于一般的ORM包不是这样.没有优选且通常可接受的方式,即使可以在技术上完美地完成,如何扩展消息.

开发和调试很简单:

  • 开发中的DEBUG模式中提供了许多其他信息(最后一帧中的"SQL"或像"myobj.save()"这样的行上的对象的类名)
  • python manage.py test --debug-sql:"在失败时打印已记录的SQL查询."
  • 使用sqlite3进行开发/测试时出现的相同错误更易于阅读.

...但你可能要求在生产中出现运行时错误.

我想在一个如此笼统的问题中你的可能意图,你可能会感兴趣的方向.

A)从最重要的信息回溯通常是几行上方的多行用".../Django的/ DB/...".这对一个大师来说非常容易.如果代码不像Django管理站点那样动态和通用,很可能使用它,其中没有代码接近myobj.save()调用(在父帧中都没有)包含显式模型名称.例:

# skip some initial universal code in ".../django/..."
...
# our apps start to be interesting... (maybe other installed app)
...
# START HERE: Open this line in the editor. If the function is universal, jump to the previous.
File ".../me/app/...py", line 47, in my...
  my_obj.save()
# skip many stack frames .../django/db/... below
File ".../django/db/models/base.py", line 734, in save
  # self.save_base(...    # this line 733 is not visible
      force_update=force_update, update_fields=update_fields)
...
# interesting only sql and params, but not visible in production
File ".../django/db/backends/utils.py", line 64, in execute
  return self.cursor.execute(sql, params)
IntegrityError (or DataError similarly)...
Run Code Online (Sandbox Code Playgroud)

B)通过模型的共同祖先捕获信息

class ...(models.Model):
    def save(self, *args, **wkargs):
        try:
            super(..., self).save(*args, **wkargs)
        except django.db.utils.IntegrityError as exc:
            new_message = 'table {}'.format(self._meta.db_table)
            exc.extra_info = new_message
            # this is less compatible, but it doesn't require additional reading support
            # exc.args = exc.args + (new_message,)
            reraise
Run Code Online (Sandbox Code Playgroud)

这可能会使多重继承的调试变得复杂.

C)Django数据库中实现会更好,但我无法想象它会被接受而不会在某些问题之后被还原.