什么是Django South GhostMigrations异常以及如何调试它?

时间:2012-01-16 03:23:57

标签: django django-models django-south

对我的Django应用程序模型进行了一些更改,并使用South在我的开发机器上迁移它们(迁移0004到0009)。但是当尝试在服务器上迁移这些更改时,我收到“GhostMigrations”错误。

没有太多好的内容可以解释ghost迁移是什么,或者如何调试它。 Google对此没有帮助,其他提及幽灵迁移的SO问题也没有涵盖这一点(最有用的问题here主要是关于工作流程)。 django-south IRC中有用的人对此进行了关于鬼迁移的说法:“这意味着南方的历史(数据库中的一个表)记录了它认为已经应用的两个迁移,但其迁移文件无法找到” 。我现在想弄清楚如何完成调试。

提前感谢您的帮助。

以下是错误:

Traceback (most recent call last):
  File "manage.py", line 14, in <module>
    execute_manager(settings)
  File "/home/username/webapps/myproject/lib/python2.6/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/home/username/webapps/myproject/lib/python2.6/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/username/webapps/myproject/lib/python2.6/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/username/webapps/myproject/lib/python2.6/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/home/username/lib/python2.6/South-0.7.3-py2.6.egg/south/management/commands/migrate.py", line 105, in handle
    ignore_ghosts = ignore_ghosts,
  File "/home/username/lib/python2.6/South-0.7.3-py2.6.egg/south/migration/__init__.py", line 171, in migrate_app
    applied = check_migration_histories(applied, delete_ghosts, ignore_ghosts)
  File "/home/username/lib/python2.6/South-0.7.3-py2.6.egg/south/migration/__init__.py", line 88, in check_migration_histories
    raise exceptions.GhostMigrations(ghosts)
south.exceptions.GhostMigrations: 

 ! These migrations are in the database but not on disk:
    <bodyguard: 0002_auto__add_field_asset_is_reserved__add_field_asset_is_created__add_fie>
    <bodyguard: 0003_auto__del_field_asset_is_reserved__add_field_asset_is_assigned>
 ! I'm not trusting myself; either fix this yourself by fiddling
 ! with the south_migrationhistory table, or pass --delete-ghost-migrations
 ! to South to have it delete ALL of these records (this may not be good).

我很惊讶地看到南方抱怨迁移0002和0003,因为我几个月前做了这些改变。我今天早些时候做出的改变是改变了0004到0009。

这是我的模特:

class Asset(models.Model):
    title = models.CharField(max_length=200, blank=True, null=True)
    user = models.ForeignKey(User, blank=True, null=True) 
    is_assigned = models.NullBooleanField(blank=True, null=True) 
    is_created = models.NullBooleanField(blank=True, null=True) 
    is_active = models.NullBooleanField(blank=True, null=True)
    activation_date = models.DateTimeField(default=datetime.datetime.now, blank=True, null=True)

class AssetEdit(models.Model):
    asset = models.ForeignKey(Asset, related_name="edits", blank=True, null=True)
    update_date = models.DateTimeField(default=datetime.datetime.now, blank=True, null=True)

以下是南迁移文件夹的内容:

0001_initial.py
0001_initial.pyc
0002_auto__chg_field_asset_username__chg_field_asset_title__chg_field_asset.py
0002_auto__chg_field_asset_username__chg_field_asset_title__chg_field_asset.pyc
0003_auto__add_field_asset_is_reserved__add_field_asset_is_created__add_fie.py
0003_auto__add_field_asset_is_reserved__add_field_asset_is_created__add_fie.pyc
0004_auto__del_field_asset_is_reserved__add_field_asset_is_assigned.py
0004_auto__del_field_asset_is_reserved__add_field_asset_is_assigned.pyc
0005_auto__add_assetedit.py
0005_auto__add_assetedit.pyc
0006_auto__del_field_assetedit_user__add_field_assetedit_asset.py
0006_auto__del_field_assetedit_user__add_field_assetedit_asset.pyc
0007_auto__chg_field_assetedit_update_date.py
0007_auto__chg_field_assetedit_update_date.pyc
0008_auto__add_field_asset_activated_date.py
0008_auto__add_field_asset_activated_date.pyc
0009_auto__del_field_asset_activated_date__add_field_asset_activation_date.py
0009_auto__del_field_asset_activated_date__add_field_asset_activation_date.pyc
__init__.py
__init__.pyc

这是south_migrationtable:

 id | app_name  |                                  migration                                  |            applied            
----+-----------+-----------------------------------------------------------------------------+-------------------------------
  1 | myapp     | 0001_initial                                                                | 2011-10-14 22:07:11.467184-05
  2 | myapp     | 0002_auto__add_field_asset_is_reserved__add_field_asset_is_created__add_fie | 2011-10-14 22:07:11.469822-05
  3 | myapp     | 0003_auto__del_field_asset_is_reserved__add_field_asset_is_assigned         | 2011-10-14 22:07:11.471799-05
(3 rows)

这是目前的myapp_asset表:

                                   Table "public.myapp_asset"
   Column    |          Type          |                          Modifiers                           
-------------+------------------------+--------------------------------------------------------------
 id          | integer                | not null default nextval('myapp_asset_id_seq'::regclass)
 title       | character varying(200) | 
 user_id     | integer                | 
 is_assigned | boolean                | 
 is_created  | boolean                | 
 is_active   | boolean                | 
Indexes:
    "myapp_asset_pkey" PRIMARY KEY, btree (id)
    "myapp_asset_user_id" btree (user_id)
Foreign-key constraints:
    "myapp_asset_user_id_fkey" FOREIGN KEY (user_id) REFERENCES auth_user(id) DEFERRABLE INITIALLY DEFERRED

我无法弄清楚为什么 django-south认为迁移0002和0003是“Ghosts”。它们都在迁移文件夹中,在迁移表中列为“已应用”,并且数据库似乎与迁移0003后的结束状态一致。

(可能的错误:迁移文件夹包含在git repo中;迁移0002创建了一个属性,然后0003重命名了它)

2 个答案:

答案 0 :(得分:23)

不知何故,您的数据库记录了在迁移文件夹中找不到的迁移0002和0003。

文件系统中的迁移00020002_auto__chg_field_asset_username__chg_field_asset_title__chg_field_asset.py,而历史记录表中的迁移为0002_auto__add_field_asset_is_reserved__add_field_asset_is_created__add_fie.py

当您的迁移文件夹具有不同的内容(可能正在开发中?)时,必须迁移到南方。

根据您所说的内容,我认为您的数据库反映了迁移时的状态0004,因此我会运行一个python manage.py migrate myapp 0004 --fake --delete-ghost-migrations,它会将迁移表设置为您添加了is_assigned字段,您可以愉快地应用迁移0005+

您最了解当前数据库表应该匹配哪个迁移!

答案 1 :(得分:7)

它们被视为ghost迁移,因为数据库中的名称为:

0002_auto__add_field_asset_is_reserved__add_field_asset_is_created__add_fie
0003_auto__del_field_asset_is_reserved__add_field_asset_is_assigned

与您列出的文件名不匹配:

0003_auto__add_field_asset_is_reserved__add_field_asset_is_created__add_fie.py
0004_auto__del_field_asset_is_reserved__add_field_asset_is_assigned.py

数字是文件名的一部分,必须完美匹配。我不确定你是如何达到这种状态的,但是如果你完全确定你的数据库与0004文件中的数据库匹配,你可以将0002_auto__chg_field_asset_username__chg_field_asset_title__chg_field_asset添加到南数据库表中,然后更新这两行以便数字匹配您的文件名。

毋庸置疑,在此之前你应该备份所有内容。