9

我有这个代码:

try:
    parent_comment = models.Comment.all_objects.get(id=parent_comment_id)
except models.Comment.DoesNotExist:
    parent_comment = None

if parent_comment is not None and parent_comment_id is None:
    raise Exception("WTF django/mysql")

...有时,异常会以某种方式引发。这怎么可能发生?

偶尔,一天几次,它返回看似随机的 Comment 实例。通常它会按预期运行并返回 None。

这是 Comment 表的 id 字段:id int(11) NOT NULL AUTO_INCREMENT所以它不是可以为空的。这是一个 InnoDB 表。

至于 Comment.all_objects,这是它​​的定义:all_objects = Manager()它是该类的第一行。

我们在 Django 1.2.7 上。

更新 向异常添加了日志记录,以获取引发异常时生成的 SQL。这里是:

SELECT `canvas_comment`.`id`, `canvas_comment`.`visibility`, `canvas_comment`.`parent_content_id`, `canvas_comment`.`parent_comment_id`, `canvas_comment`.`timestamp`, `canvas_comment`.`reply_content_id`, `canvas_comment`.`reply_text`, `canvas_comment`.`replied_comment_id`, `canvas_comment`.`category_id`, `canvas_comment`.`author_id`, `canvas_comment`.`title`, `canvas_comment`.`ip`, `canvas_comment`.`anonymous`, `canvas_comment`.`score`, `canvas_comment`.`judged`, `canvas_comment`.`ot_hidden` FROM `canvas_comment` WHERE `canvas_comment`.`id` IS NULL
4

2 回答 2

13

这种行为是由非常奇怪的(在这个编码员的拙见中)MySQL 行为引起的,SQL_AUTO_IS_NULL变量控制(1默认情况下在 MySQL < 5.5.3 中):

如果此变量设置为 1,则在成功插入自动生成的 AUTO_INCREMENT 值的语句之后,您可以通过发出以下形式的语句来找到该值:

SELECT * FROM tbl_name WHERE auto_col IS NULL

如果语句返回一行,则返回的值与调用 LAST_INSERT_ID() 函数时相同

一个 Django 错误(已关闭:wontfix)描述了由此“功能”引起的类似混淆,其中一位核心开发人员指出

如果您不想要这种行为,您应该配置您的数据库以根据您的偏好做正确的事情

那么,解决方案是使用语句SQL_AUTO_IS_NULL禁用MySQL 数据库的选项。您可以通过以下方式执行此操作:SETsettings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        # ... your DB options
        'OPTIONS': {
            'init_command': 'SET SQL_AUTO_IS_NULL=0;'
        },
    }
}

从长远来看,您可以尝试在 django-developers 列表上打鼓,让他们重新考虑之前的立场

幸运的是,我在这里的想法并没有烧毁任何桥梁。如果有人想测试它,或者默认使用它,他们可以通过设置中的 DATABASE_OPTIONS 使用数据库初始化选项......“read_default_file”和“init_command”在那里都很有用。

我并不是说这应该是“不,永远”,但现在我不相信这样做值得。与此相平衡的是如何让人们知道它可能会发生……耸耸肩……我可能会在 databases.txt 中添加一些内容,作为开始。我讨厌这种平衡行为。:-(

于 2012-08-10T19:37:22.140 回答
1

排除简单的东西:

  1. 你能发布你的评论模型吗
  2. 您能否对您的数据库运行以下查询

SELECT COUNT(id) FROM <your_comment_table> WHERE id <= 0 OR id ='' OR id IS NULL

你的代码在逻辑上应该可以工作,除非你的模型代码中有一些不可靠的东西,这让我相信它一定是与数据相关的。

编辑

另一个想法,看看 django 的 ORM 正在查询什么(这应该告诉我们发生了什么):

parent_comment = models.Comment.all_objects.get(id=parent_comment_id)
raise Exception(parent_comment.query) # should display out the query thats being generated
于 2012-08-10T17:55:28.663 回答