重命名auth_user会在新设置中中断迁移

时间:2014-07-24 08:06:58

标签: django django-south

看似good advice之后,我通过迁移将auth.User重命名为app.User,从Django的内置auth_user迁移到我自己的app_user 。到目前为止一切顺利,这很好。当我设置一台新机器时会出现问题。

settings.py AUTH_USER_MODEL = 'app.User'syncdb。因此,当我运行auth_user时,未创建migrate表,因此当我AUTH_USER_MODEL时,该迁移失败。

我发现的唯一方法是修改auth.User以指向syncdb,运行AUTH_USER_MODEL并迁移直至重命名迁移,然后更改{{1}}返回,然后运行其余的迁移。

有解决这个问题的方法吗?

3 个答案:

答案 0 :(得分:3)

根据您提到的问题,我首先尝试的方法是修改执行表重命名的迁移,以检查是否应该执行重命名。不幸的是,南does not readily cooperate有这种检查。如果迁移失败,大多数更高级别的操作都会完全中止迁移。但是,您可以使用db.execute,如果失败,引发异常。类似的东西:

from django.db.utils import ProgrammingError
from south.db import db

exists = False
db.start_transaction()
try:
    # Will fail if the destination table does not exist. 
    # Any typo here will yield incorrect results. Be careful.
    db.execute("select count(*) from auth_user")
    # If we get here, the table exists
    exists = True
except ProgrammingError:
    pass

# Always end the transaction we started, rollback or commit shouldn't matter.
db.rollback_transaction()

if exists:
    db.rename_table...
else:
    # The table does not exist, create new one.
    db.create_table...

我的测试表明,总是可以捕获South的数据库调用引发的错误。 然而,South在SQL错误后不会清理。 (这是我在本答案的第一个版本中最初错过的。)因此,即使捕获到异常,将启动的 next SQL操作也会发现连接处于错误状态。换句话说,失败操作之后发生的操作将因前一操作失败而失败。这是db.start_transaction()db.rollback_transaction()来电的原因。即使出现SQL错误,这也会使操作干净利落。

答案 1 :(得分:1)

我也试图像你一样遵循相同的指示,但我选择以另一种方式修复它。我创建了我的模型(称为UserProfile),如下所示:

class UserProfile(AbstractUser):
    # Fields
    ...
    class Meta:
        swappable = 'AUTH_USER_MODEL'
        db_table = 'auth_user'

这样,运行syncdb将不再导致问题,因为您的表名称正确。但是,我不记得我在做这个时所采取的所有步骤,因此可能需要更多设置。

答案 2 :(得分:1)

根据这里提出的其他答案的想法,这是一个有效的解决方案:

def forwards(self, orm):
    if 'auth_user' not in db.execute('SHOW TABLES'):
        db.create_table('app_user', (
            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('password', self.gf('django.db.models.fields.CharField')(max_length=128)),
            ('last_login', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
            ('is_superuser', self.gf('django.db.models.fields.BooleanField')(default=False)),
            ('username', self.gf('django.db.models.fields.CharField')(unique=True, max_length=30)),
            ('first_name', self.gf('django.db.models.fields.CharField')(max_length=30, blank=True)),
            ('last_name', self.gf('django.db.models.fields.CharField')(max_length=30, blank=True)),
            ('email', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True)),
            ('is_staff', self.gf('django.db.models.fields.BooleanField')(default=False)),
            ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)),
            ('date_joined', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
        ))
        db.send_create_signal(app', ['User'])
    else:
        db.rename_table('auth_user', 'app_user')