迁移到1.2.5后,Django测试失败 - 儿童模型的主要关键问题

时间:2011-04-05 15:30:40

标签: python django postgresql

我有一个继承自模型Object的模型ThreadedComment。 ThreadedComment没有自己独特的主键,依赖于Object的前缀键(“ID”)。这就是模型的构建方式:

class Object(models.Model):
    permalink = models.CharField(max_length=128)
    status = models.IntegerField()
    version = models.IntegerField()

class ThreadedComment(Object):
    parent = models.ForeignKey('self', null=True, blank=True, default=None, related_name='children')
    parent_object = models.OneToOneField(Object, parent_link=True)
    # other fields follow

直到django 1.2.3这很好用但是当我升级到django 1.2.5(1.3有相同的问题)时,当我尝试运行任何测试时会发生这种情况:

Error: Database test_db couldn't be flushed. Possible reasons:
  * The database isn't running or isn't configured correctly.
  * At least one of the expected database tables doesn't exist.
  * The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
The full error: relation "threadedcomments_threadedcomment_id_seq" does not exist
LINE 1: SELECT setval('"threadedcomments_threadedcomment_id_seq"', 1...

问题在于“sqlflush”命令生成并执行SQL文件。有问题的一行是:

SELECT setval(pg_get_serial_sequence('"threadedcomments_threadedcomment"','id'), 1, false);

这显然失败了,因为该表中没有“id”列。

什么是有趣的,django 1.2.3版本产生类似的输出:

SELECT setval('"threadedcomments_threadedcomment_id_seq"', 1, false);

但是测试仍在继续,所以我之前没有注意到这个问题。

我在这里做错了什么?模型定义是否不正确,即我是否需要在threadcomment中拥有主键,即使我不需要它与对象具有一对一的关系?为什么它从1.0到1.1一直运行到1.2.3,现在在1.2.5中断?

3 个答案:

答案 0 :(得分:4)

原来这是一个django bug。详情请见http://code.djangoproject.com/ticket/12728

以下是我们的临时解决方法:https://bitbucket.org/filmaster/filmaster-test/changeset/afbac905cf63

答案 1 :(得分:0)

我无法在主干或1.2.3上重现它;我创建了一个包含app'threadcomments'的新项目,以及您发布的模型,结果如下:

BEGIN;
TRUNCATE "threadedcomments_threadedcomment", "auth_permission", "auth_group", "auth_group_permissions", "django_session", "auth_user_groups", "auth_user_user_permissions", "threadedcomments_object", "auth_message", "django_site", "auth_user", "django_content_type";
SELECT setval(pg_get_serial_sequence('"auth_permission"','id'), 1, false);
SELECT setval(pg_get_serial_sequence('"auth_group"','id'), 1, false);
SELECT setval(pg_get_serial_sequence('"auth_user"','id'), 1, false);
SELECT setval(pg_get_serial_sequence('"auth_message"','id'), 1, false);
SELECT setval(pg_get_serial_sequence('"django_content_type"','id'), 1, false);
SELECT setval(pg_get_serial_sequence('"django_site"','id'), 1, false);
SELECT setval(pg_get_serial_sequence('"threadedcomments_object"','id'), 1, false);
COMMIT;

从不创建序列threadedcomments_threadedcomment_id_seq,Django不会尝试刷新它。我认为这不是版本更改相关的错误(而是一直存在的东西,但却没有引起注意)。

答案 2 :(得分:0)

你说,“ThreadedComment没有自己独特的主键,依赖于Object的promary [sic]键('ID')。” Django要求将一个字段标识为主键。请参阅Automatic primary key fields

更多细节。 。

函数pg_get_serial_sequence()返回特定列使用的序列的名称。因此,以下语句表示“获取表'threadcomments_threadedcomment'中'id'列所用序列的名称,将序列的last_value字段设置为1,并在下次调用nextval()时返回1。

SELECT setval(pg_get_serial_sequence('"threadedcomments_threadedcomment"','id'), 1, false);

但是这句话

SELECT setval('"threadedcomments_threadedcomment_id_seq"', 1, false);

表示“将名为'threadedcomments_threadedcomment_id_seq'的序列的last_value字段设置为1,并在下次调用nextval()时返回1.”

我的猜测是Django用于命名版本之间更改的序列的算法。我已经看到其他系统进行类似的更改,因为通过连接表和列名称构建的标识符变得太长。我认为Oracle标识符有30个字符的限制;您的标识符是39个字符。我已经看到Rails生成70多个字符标识符,这些标识符在PostgreSQL上打破(63或64个字符限制)。