成功运行新迁移(向现有表添加新列)后,在同一个表(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...
^
它们由Django的单元测试运行。 As you know, South runs "every migration every time you run your tests."
我(以及其他)有三个表: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
可能有些特别。
我向publisher_id
和users
添加了games
列,如下所示:
# Same for both 'users' and 'games'
publisher = models.ForeignKey('ymc.Publisher', blank=True, null=True, default=None)
以下是已开始失败的现有迁移:
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'})
},
...
}
--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...
滚动所有内容并再次尝试(完全相同的结果)。
非常希望这是一个梦想。
男人......除此之外,并不多。我非常困惑。我甚至没有 了解生成此错误消息的位置:
LINE 1: ...dress", "users"."gender", "users"."developer_id", "users"."p...
^ Like,
LINE 1:
什么,对吧?
答案 0 :(得分:0)
您能提供由南方生成的完整迁移文件吗?
修改强>
迁移似乎是正确的,只是想看看是否有人摆弄它。但有时候你必须摆弄周围的东西才能让它们变得平直。我建议你移动与模型数据相关的代码,即
users = User.objects.all()
for user in users:
user.registered_at = user.joined_at
user.save()
进入单独的迁移。要创建空白迁移,请使用其中forward
&的任何代码的迁移文件。 backward
种方法,使用python manage.py datamigration app_name file_name
并在转发方法中添加上述代码。
我希望这对你有用..
答案 1 :(得分:0)
问题是迁移0010
中的以下代码:
from ymc.model.users import User
...
users = User.objects.all()
for user in users:
user.registered_at = user.joined_at
user.save()
我认为这一定是由构建系统并且不再在这里的人添加的。他聪明而且很棒,但没有人是完美的。 According to the South docs on data migrations,您需要使用orm.YourModel
,否则将使用当前架构。这就是South /数据库看到新publisher_id
列的原因。
该块应该是:
users = orm.User.objects.all()
for user in users:
user.registered_at = user.joined_at
user.save()