我有这个代码:
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。
这是注释表的 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
这种行为是由非常奇怪的(以这个程序员的拙见)MySQL行为引起的,该行为由SQL_AUTO_IS_NULL
变量控制(在MySQL <5.5.3中默认1
):
如果此变量设置为 1,则在成功插入自动生成的 AUTO_INCREMENT 值的语句之后,可以通过发出以下形式的语句来查找该值:
SELECT * FROM tbl_name WHERE auto_col IS NULL
如果语句返回一行,则返回的值与调用 LAST_INSERT_ID() 函数时的值相同
有一个 Django 错误(关闭:wontfix)描述了由这个"功能"引起的类似混乱,其中核心开发人员声明
如果您不希望这种行为,则应将数据库配置为根据您的偏好执行正确的操作
然后,解决方案是使用 SET
语句禁用 MySQL 数据库的SQL_AUTO_IS_NULL
选项。您可以在settings.py
中执行此操作,如下所示:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
# ... your DB options
'OPTIONS': {
'init_command': 'SET SQL_AUTO_IS_NULL=0;'
},
}
}
从长远来看,你可以尝试在django开发者名单上敲打鼓,让他们重新考虑他们之前的立场:
幸运的是,我在这里的想法并没有烧毁任何桥梁。如果有人 想要测试一下,或者默认使用它,他们可以使用数据库 通过设置中的DATABASE_OPTIONS初始化选项...双 "read_default_file"和"init_command"在那里很有用。
我不是说这应该是"不,永远",但现在我不是 确信这样做是值得的。与之平衡的是如何让 人们知道它可能会发生...耸耸肩..我可能会添加一些东西 数据库.txt,首先。我讨厌这种平衡行为。
排除简单的东西:
- 你能发布你的评论模型吗
- 您能否对数据库运行以下查询
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