Django migration strategy for renaming a model and relationship fields
Django migration strategy for renaming a model and relationship fields
I'm planning to rename several models in an existing Django project where there are many other models that have foreign key relationships to the models I would like to rename. I'm fairly certain this will require multiple migrations, but I'm not sure of the exact procedure.
Let's say I start out with the following models within a Django app called myapp
:
class Foo(models.Model): name = models.CharField(unique=True, max_length=32) description = models.TextField(null=True, blank=True) class AnotherModel(models.Model): foo = models.ForeignKey(Foo) is_awesome = models.BooleanField() class YetAnotherModel(models.Model): foo = models.ForeignKey(Foo) is_ridonkulous = models.BooleanField()
I want to rename the Foo
model because the name doesn't really make sense and is causing confusion in the code, and Bar
would make for a much clearer name.
From what I have read in the Django development documentation, I'm assuming the following migration strategy:
Step 1
Modify models.py
:
class Bar(models.Model): # <-- changed model name name = models.CharField(unique=True, max_length=32) description = models.TextField(null=True, blank=True) class AnotherModel(models.Model): foo = models.ForeignKey(Bar) # <-- changed relation, but not field name is_awesome = models.BooleanField() class YetAnotherModel(models.Model): foo = models.ForeignKey(Bar) # <-- changed relation, but not field name is_ridonkulous = models.BooleanField()
Note the AnotherModel
field name for foo
doesn't change, but the relation is updated to the Bar
model. My reasoning is that I shouldn't change too much at once and that if I changed this field name to bar
I would risk losing the data in that column.
Step 2
Create an empty migration:
python manage.py makemigrations --empty myapp
Step 3
Edit the Migration
class in the migration file created in step 2 to add the RenameModel
operation to the operations list:
class Migration(migrations.Migration): dependencies = [ ('myapp', '0001_initial'), ] operations = [ migrations.RenameModel('Foo', 'Bar') ]
Step 4
Apply the migration:
python manage.py migrate
Step 5
Edit the related field names in models.py
:
class Bar(models.Model): name = models.CharField(unique=True, max_length=32) description = models.TextField(null=True, blank=True) class AnotherModel(models.Model): bar = models.ForeignKey(Bar) # <-- changed field name is_awesome = models.BooleanField() class YetAnotherModel(models.Model): bar = models.ForeignKey(Bar) # <-- changed field name is_ridonkulous = models.BooleanField()
Step 6
Create another empty migration:
python manage.py makemigrations --empty myapp
Step 7
Edit the Migration
class in the migration file created in step 6 to add the RenameField
operation(s) for any related field names to the operations list:
class Migration(migrations.Migration): dependencies = [ ('myapp', '0002_rename_fields'), # <-- is this okay? ] operations = [ migrations.RenameField('AnotherModel', 'foo', 'bar'), migrations.RenameField('YetAnotherModel', 'foo', 'bar') ]
Step 8
Apply the 2nd migration:
python manage.py migrate
Aside from updating the rest of the code (views, forms, etc.) to reflect the new variable names, is this basically how the new migration functionality would work?
Also, this seems like a lot of steps. Can the migration operations be condensed in some way?
Thanks!
Answer by wasabigeek for Django migration strategy for renaming a model and relationship fields
So when I tried this, it seems you can condense Step 3 - 7:
class Migration(migrations.Migration): dependencies = [ ('myapp', '0001_initial'), ] operations = [ migrations.RenameModel('Foo', 'Bar'), migrations.RenameField('AnotherModel', 'foo', 'bar'), migrations.RenameField('YetAnotherModel', 'foo', 'bar') ]
You may get some errors if you don't update the names where it's imported e.g. admin.py and even older migration files (!)
Answer by John Q for Django migration strategy for renaming a model and relationship fields
I needed to do the same thing. I changed the model all at once (i.e., step 1 and step 5 together). Then created a schema migration but edited it to be this:
class Migration(SchemaMigration): def forwards(self, orm): db.rename_table('Foo','Bar') def backwards(self, orm): db.rename_table('Bar','Foo')
This worked perfectly. All my existing data showed up, all the other tables referenced Bar fine.
from here: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
Answer by v.thorey for Django migration strategy for renaming a model and relationship fields
At first, I thought that Fiver's method worked for me because the migration worked well until step 4. However, the implicit changes 'ForeignKeyField(Foo)' into 'ForeignKeyField(Bar)' was not related in any migrations. This is why migration failed when I wanted to rename relationship fields (step 5-8). This might be due to the fact that my 'AnotherModel' and 'YetAnotherModel' are dispatched in other apps in my case.
So I managed to rename my models and relationship fields doing following below steps:
I adapted the method from this and particularly the trick of otranzer.
So like Fiver let's say we have in myapp:
class Foo(models.Model): name = models.CharField(unique=True, max_length=32) description = models.TextField(null=True, blank=True)
And in myotherapp:
class AnotherModel(models.Model): foo = models.ForeignKey(Foo) is_awesome = models.BooleanField() class YetAnotherModel(models.Model): foo = models.ForeignKey(Foo) is_ridonkulous = models.BooleanField()
Step 1:
Transform every OntToOneField(Foo) or ForeignKeyField(Foo) into IntegerField(). (This will keep the id of related Foo object as value of the integerfield).
class AnotherModel(models.Model): foo = models.IntegerField() is_awesome = models.BooleanField() class YetAnotherModel(models.Model): foo = models.IntegerField() is_ridonkulous = models.BooleanField()
Then
python manage.py makemigrations python manage.py migrate
Step 2: (Like step 2-4 from Fiver)
Change the model name
class Bar(models.Model): # <-- changed model name name = models.CharField(unique=True, max_length=32) description = models.TextField(null=True, blank=True)
Create an empty migration:
python manage.py makemigrations --empty myapp
Then edit it like:
class Migration(migrations.Migration): dependencies = [ ('myapp', '0001_initial'), ] operations = [ migrations.RenameModel('Foo', 'Bar') ]
Eventually
python manage.py migrate
Step 3:
Transform Back your IntegerField() into their previous ForeignKeyField, OneToOneField but with the new Bar Model. (The previous integerfield was storing the id, so django understand that and reestablish the connection, which is cool.)
class AnotherModel(models.Model): foo = models.ForeignKey(Bar) is_awesome = models.BooleanField() class YetAnotherModel(models.Model): foo = models.ForeignKey(Bar) is_ridonkulous = models.BooleanField()
Then do:
python manage.py makemigrations
Very importantly, at this step you have to modify every new migrations and add the dependency on the RenameModel Foo-> Bar migrations. So if both AnotherModel and YetAnotherModel are in myotherapp the created migration in myotherapp must look like this:
class Migration(migrations.Migration): dependencies = [ ('myapp', '00XX_the_migration_of_myapp_with_renamemodel_foo_bar'), ('myotherapp', '00xx_the_migration_of_myotherapp_with_integerfield'), ] operations = [ migrations.AlterField( model_name='anothermodel', name='foo', field=models.ForeignKey(to='myapp.Bar'), ), migrations.AlterField( model_name='yetanothermodel', name='foo', field=models.ForeignKey(to='myapp.Bar') ), ]
Then
python manage.py migrate
Step 4:
Eventually you can rename your fields
class AnotherModel(models.Model): bar = models.ForeignKey(Bar) <------- Renamed fields is_awesome = models.BooleanField() class YetAnotherModel(models.Model): bar = models.ForeignKey(Bar) <------- Renamed fields is_ridonkulous = models.BooleanField()
and then do automatic renaming
python manage.py makemigrations
(django should ask you if you actually renamed the modelname, say yes)
python manage.py migrate
And that's it!
This works on Django1.8
Answer by ups for Django migration strategy for renaming a model and relationship fields
Unfortunatelly, I found problems (each django 1.x) with rename migration which leave old tablenames in db (don't even try anything on old table, just rename model).
Solution for that case:
class Foo(models.Model): name = models.CharField(unique=True, max_length=32) ... Bar = Foo
Answer by Curtis Lo for Django migration strategy for renaming a model and relationship fields
I also faced the problem as v.thorey described and found that his approach is very useful but can be condensed into fewer steps which are actually step 5 to 8 as Fiver described without step 1 to 4 except that step 7 needs to be changed as my below step 3. The overall steps are as follow:
Step 1: Edit the related field names in models.py
class Bar(models.Model): name = models.CharField(unique=True, max_length=32) description = models.TextField(null=True, blank=True) class AnotherModel(models.Model): bar = models.ForeignKey(Bar) # <-- changed field name is_awesome = models.BooleanField() class YetAnotherModel(models.Model): bar = models.ForeignKey(Bar) # <-- changed field name is_ridonkulous = models.BooleanField()
Step 2: Create an empty migration
python manage.py makemigrations --empty myapp
Step 3: Edit the Migration class in the migration file created in Step 2
class Migration(migrations.Migration): dependencies = [ ('myapp', '0001_initial'), ] operations = [ migrations.AlterField( model_name='AnotherModel', name='foo', field=models.IntegerField(), ), migrations.AlterField( model_name='YetAnotherModel', name='foo', field=models.IntegerField(), ), migrations.RenameModel('Foo', 'Bar'), migrations.AlterField( model_name='AnotherModel', name='foo', field=models.ForeignKey(to='myapp.Bar'), ), migrations.AlterField( model_name='YetAnotherModel', name='foo', field=models.ForeignKey(to='myapp.Bar'), ), migrations.RenameField('AnotherModel', 'foo', 'bar'), migrations.RenameField('YetAnotherModel', 'foo', 'bar') ]
Step 4: Apply the migration
python manage.py migrate
Done
P.S. I've tried this approach on Django 1.9
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment