开发者

Renaming a django model class-name and corresponding foreign keys with south, without loosing the data

Following 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 the underscores from all the class names so that User_History looks UserHistory, also the foreign keys should be updated. I tried using south but could not find it in the documentaion.

One way is export the data, uninstall south, delete mi开发者_如何学JAVAgration, rename the table and then import data again. Is there any other way to do it?


You can do this using just South.

For this example I have an app called usergroups with the following model:

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

which I assume is already under migration control with South.

Make the model name change:

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

and create an empty migration from south

$ python manage.py schemamigration usergroups model_name_change --empty

This will create a skeleton migration file for you to specify what happens. If we edit it so it looks like this (this file will be in the app_name/migrations/ folder -- usergroups/migrations/ 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 we are renaming the database table name to match what the django ORM will look for with the new model name. We reverse the change in backwards to ensure the migration can be stepped back if required.

Run the migration with no need to import/export the exisiting data:

$ python manage.py migrate

The only step remaining is to update the foreign key and many-to-many columns in the models that refer to myUser_Group and change to refer to MyUserGroup.


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

In your model make sure you have your new table name in:

class Meta:
        db_table = new_table_name'

Then like mmcnickle suggested, create a custom migration:

python manage.py schemamigration xyz migration_name --empty

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

Now with your custom migration also add the line to rename your table forward and backwards:

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

This can be enough to migrate and change the table name but if you have been using the Class Meta custom table name before then you'll have to do a bit more. So I would say as a rule, just to be safe do a search in your migration file for "old_table_name" and change any entries you find to the new table name. For example, if you were previously using the Class Meta custom table name, you will likely see:

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

So you'll need to change that old table name to the new one.

Now you can migrate with:

python manage.py migrate xyz

At this point your app should run since all you have done is change the table name and tell Django to look for the new table name.

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

After you do this your app should run fine. At this point your task is pretty much accomplished and your app should run fine with a new model name and new table name. The only problem you will run into using South is the next time you create a migration using it's auto detection feature it will try to drop the old table and create a new one from scratch because it has detected 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

The nice thing is here you do nothing since you have already changed your model name so South picks this up. Just migrate with "pass" in the migrate forwards and backwards:

python manage.py migrate xyz

Nothing is done and South now realizes it is up to date. Try:

python manage.py schemamigration xyz --auto

and you should see it detects nothing has changed

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜