【发布时间】:2013-12-13 20:50:40
【问题描述】:
A.摘要:
在成功运行新迁移(将新列添加到现有表)后,在同一个表 (0010) 上运行的早期迁移失败并显示:
Creating test database for alias 'default'...
Got an error creating the test database: database "test_ymc_platform" already exists
Type 'yes' if you would like to try deleting the test database 'test_ymc_platform', or 'no' to cancel:
当我回复 yes:
Error in migration: ymc:0010_auto__add_field_user_registered_at
DatabaseError: column users.publisher_id does not exist
LINE 1: ...dress", "users"."gender", "users"."developer_id", "users"."publisher_id...
^
B.详情:
1。这些迁移是如何运行的?
它们由 Django 的单元测试运行。 As you know, South runs "every migration every time you run your tests."
2。迁移历史
我有(除其他外)三张桌子:users、games 和 publishers。直到迁移0025,他们彼此没有任何关系。在迁移0025 中,我添加了一个外键,其中users.publisher_id 和games.publisher_id 引用publishers。
当我创建并运行 0025 时,我在 0024 并且一切都成功迁移。然后我运行了我的单元测试并得到了上述提示和错误消息。所以0025-->0024 有效,但0009-->0010 失败。
我目前的迁移历史是这样的:
$ ./manage.py migrate ymc --list
ymc
(*) 0001_initial
...
(*) 0004_auto__add_field_user_gender
...
(*) 0010_auto__add_field_user_registered_at
...
(*) 0025_auto__add_field_user_publisher__add_field_game_publisher
0004 被包含在内是为了证明 South 可以在 users 表上运行迁移而不会阻塞。也许0010 有什么特别之处。
2。新列的模型代码是什么样的?
我向users 和games 添加了publisher_id 列,如下所示:
# Same for both 'users' and 'games'
publisher = models.ForeignKey('ymc.Publisher', blank=True, null=True, default=None)
3。 South 生成了什么代码?
这是开始失败的现有迁移:
0010_auto__add_field_user_registered_at:
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'User.registered_at'
db.add_column('users', 'registered_at',
self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True),
keep_default=False)
users = User.objects.all()
for user in users:
user.registered_at = user.joined_at
user.save()
def backwards(self, orm):
# Deleting field 'User.registered_at'
db.delete_column('users', 'registered_at')
models = {
...
'ymc.user': {
'Meta': {'object_name': 'User', 'db_table': "'users'"},
'access_token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'access_token_expiry': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'developer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['ymc.Developer']", 'null': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
'facebook_access_token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'facebook_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'forgot_password_token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'forgot_password_token_expiry': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'games': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ymc.Game']", 'null': 'True', 'through': "orm['ymc.UsersGames']", 'blank': 'True'}),
'gender': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
'is_admin': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'joined_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
'registered_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'salt': ('django.db.models.fields.CharField', [], {'max_length': '128', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
},
...
}
这是新的迁移,虽然成功应用,但会导致 0010 阻塞。
0025_auto__add_field_user_publisher__add_field_game_publisher
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'User.publisher'
db.add_column('users', 'publisher',
self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['ymc.Publisher'], null=True, blank=True),
keep_default=False)
# Adding field 'Game.publisher'
db.add_column('games', 'publisher',
self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['ymc.Publisher'], null=True, blank=True),
keep_default=False)
def backwards(self, orm):
# Deleting field 'User.publisher'
db.delete_column('users', 'publisher_id')
# Deleting field 'Game.publisher'
db.delete_column('games', 'publisher_id')
models = {
...
'ymc.user': {
'Meta': {'object_name': 'User', 'db_table': "'users'"},
'access_token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'access_token_expiry': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'developer': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['ymc.Developer']", 'null': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
'facebook_access_token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'facebook_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'forgot_password_token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'forgot_password_token_expiry': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'games': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ymc.Game']", 'null': 'True', 'through': "orm['ymc.UsersGames']", 'blank': 'True'}),
'gender': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
'is_admin': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'joined_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
'publisher': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['ymc.Publisher']", 'null': 'True', 'blank': 'True'}),
'registered_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'salt': ('django.db.models.fields.CharField', [], {'max_length': '128', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
},
...
}
4。如果您使用--verbose=3 运行测试,输出是什么?
这个:
...
> ymc:0010_auto__add_field_user_registered_at
= ALTER TABLE "users" ADD COLUMN "registered_at" timestamp with time zone NULL; []
= ALTER TABLE "users" ALTER COLUMN "registered_at" TYPE timestamp with time zone, ALTER COLUMN "registered_at" DROP NOT NULL, ALTER COLUMN "registered_at" DROP DEFAULT; []
Error in migration: ymc:0010_auto__add_field_user_registered_at
- Sending post_syncdb signal for ymc: ['Game', 'UsersGames', 'User', 'Developer']
DatabaseError: column users.publisher_id does not exist
LINE 1: ...dress", "users"."gender", "users"."developer_id", "users"."p...
5。你试过什么?
回滚所有内容并重试(完全相同的结果)。
真希望这是一场梦。
-
伙计……除此之外,不多。我超级困惑。我什至不 了解此错误消息的生成位置:
LINE 1: ...dress", "users"."gender", "users"."developer_id", "users"."p... ^ Like,LINE 1:是什么,对吧?
【问题讨论】:
标签: django unit-testing migration django-south