Renaming the django model class name and associated foreign keys with south, without data loss

Below is my model:

class myUser_Group(models.Model): name = models.CharField(max_length=100) class Channel(models.Model): name = models.CharField(max_length=100) description = models.CharField(max_length=1000) belongs_to_group = models.ManyToManyField(myUser_Group) class Video(models.Model): video_url = models.URLField(max_length=300) belongs_to_channel = models.ManyToManyField(Channel) description = models.CharField(max_length=1000) tags = TagField() class UserProfile(models.Model): user = models.OneToOneField(User) class User_History(models.Model): date_time = models.DateTimeField() user = models.ForeignKey(UserProfile, null=True, blank=True) videos_watched = models.ManyToManyField(Video) 

I just wanted to remove underscores from all class names so that User_History looks like UserHistory , foreign keys should also be updated. I tried to use the south, but could not find it in the document.

One way is to export the data, delete the south, delete the migration, rename the table and then import the data again. Is there any other way to do this?

+6
source share
2 answers

You can do this using only the South.

In this example, I have an application called usergroups with the following model:

 class myUser_Group(models.Model): name = models.CharField(max_length=100) 

which, I believe, is already under the control of migration from the south.

Change the model name:

 class MyUserGroup(models.Model): name = models.CharField(max_length=100) 

and create an empty migration from the south

 $ python manage.py schemamigration usergroups model_name_change --empty 

This will create a skeleton migration file so you can indicate what will happen. If we edit it so that it looks like this (this file will be in app_name / migrations / folder - usergroups / migration / in this case):

 import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models class Migration(SchemaMigration): def forwards(self, orm): # Change the table name from the old model name to the new model name # ADD THIS LINE (using the correct table names) db.rename_table('usergroups_myuser_group', 'usergroups_myusergroup') def backwards(self, orm): # Provide a way to do the migration backwards by renaming the other way # ADD THIS LINE (using the correct table names) db.rename_table('usergroups_myusergroup', 'usergroups_myuser_group') models = { 'usergroups.myusergroup': { 'Meta': {'object_name': 'MyUserGroup'}, 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) } } complete_apps = ['usergroups'] 

In the forwards method forwards we rename the database table name according to what ORM django will look for with the new model name. We will undo the change to backwards to ensure that migration can be delayed if required.

Start the migration without having to import / export existing data:

$ python manage.py migrate

It remains only to update the foreign key columns and many-to-many in the models that reference myUser_Group, and change them to a link to MyUserGroup.

+8
source

mmcnickle solution may work and seems reasonable, but I prefer a two-step process. In the first step, you change the name of the table.

In your model, make sure you have a new table name:

 class Meta: db_table = new_table_name' 

Then, as mmcnickle suggested, create a custom migration:

 python manage.py schemamigration xyz migration_name --empty 

You can read more about this here: https://docs.djangoproject.com/en/dev/ref/models/options/

Now with your own migration, also add a line to rename the table back and forth:

 db.rename_table("old_table_name","new_table_name") 

This may be enough to transfer and change the table name, but if you used the table name of the Meta class tables before that, you will have to work a little. Therefore, I would say, as a rule, just to be safe, search your migration file for "old_table_name" and change all the entries that you find to the name of the new table. For example, if you previously used the table name of the Meta table, you will most likely see:

 'Meta': {'object_name': 'ModelNameYouWillChangeNext', 'db_table': "u'old_table_name'"}, 

So, you will need to change this name of the old table to the new one.

You can now migrate with:

 python manage.py migrate xyz 

At this point, your application should work, since all you have done is change the name of the table and tell Django to find the new table name.

The second step is to change the name of the model. The difficulty of this really depends on your application, but basically you just need to change all the code that refers to the old model name to the code that refers to the name of the new model. You probably also need to change the file names and directory names if you used your old model name in them for organization purposes.

After that, your application should work fine. At this stage, your task is largely completed, and your application should work fine with the new model name and new table name. The only problem you will encounter in using the south is the next time you create a migration using the auto-discovery feature, it will try to reset the old table and create a new one from scratch because it discovered your new model name. To fix this, you need to create another custom migration:

 python manage.py schemamigration xyz tell_south_we_changed_the_model_name_for_old_model_name --empty 

It's nice that you are not doing anything here, since you have already changed the name of your model, so South chooses this. Just go with the β€œpass” to migrate back and forth:

 python manage.py migrate xyz 

Nothing has been done, and the South now realizes that it is updated. Try:

 python manage.py schemamigration xyz --auto 

and you should see that he found that nothing has changed

+1
source

Source: https://habr.com/ru/post/897681/


All Articles