Renaming auth_user aborts migration on new setup

Following what seems like good advice , I switched from the built-in auth.User Django to my own app.User , doing a migration that renames auth_user to app_user . So far so good, it works great. The problem occurs when I set up a new machine.

In my settings.py , I have AUTH_USER_MODEL = 'app.User' . Because of this, when I run syncdb , the auth_user table auth_user not created, so when I migrate , this migration fails.

The only way to find this: change AUTH_USER_MODEL to auth.User , run syncdb and migrate before renaming, then change AUTH_USER_MODEL back and then run the rest of the migration.

Is there any way to solve this problem?

+7
django django-south
source share
3 answers

With the ideas of the other answers presented here, this is a solution that works:

 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') 
+1
source share

Based on the issues you mentioned, the approach I tried first was to change the hyphen that renames the table to check if renaming should be done. Unfortunately, the south does not work with this type of check . Most higher-level operations completely interrupt migration if they fail. However, you can use db.execute , and this will throw an exception if it fails. Something like:

 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... 

My tests show that you can always catch errors caused by calls to the South database. However, the south is not cleared after an SQL error. (This is what I initially missed in the first version of this answer.) Therefore, even if an exception is caught, the next SQL operation that is run will find that the connection is in an error state. In other words, an operation that occurs after a failed operation will fail because the previous operation failed. This is the cause of the calls to db.start_transaction() and db.rollback_transaction() . This makes the operation clean even if an SQL error occurs.

+3
source share

I also had problems trying to follow the same instructions as you, but I decided to fix it differently. I created my model (called UserProfile) as follows:

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

Thus, running syncdb will no longer cause problems because your table is named correctly. However, I don’t remember exactly all the steps that I took when I did this, so a little more tweaking may be required.

+1
source share

All Articles