使用South重命名Django模型类名及相应外键,数据不丢失

6 投票
2 回答
5160 浏览
提问于 2025-04-17 02:41

以下是我的模型:

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)

我只是想把所有类名中的下划线去掉,这样User_History就变成UserHistory,同时外键也需要更新。我尝试过使用south,但在文档中找不到相关信息。

一种方法是导出数据,卸载south,删除迁移,重命名表格,然后再导入数据。还有其他方法吗?

2 个回答

1

mmcnickle的解决方案可能有效,而且看起来合理,但我更喜欢分两步来做。第一步是更改表的名称。

在你的模型中,确保你已经把新的表名放在:

class Meta:
        db_table = new_table_name'

然后像mmcnickle建议的那样,创建一个自定义迁移:

python manage.py schemamigration xyz migration_name --empty

你可以在这里了解更多信息: https://docs.djangoproject.com/en/dev/ref/models/options/

现在在你的自定义迁移中,也要添加一行代码来前后都重命名你的表:

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

这可能足以迁移并更改表名,但如果你之前使用过Class Meta自定义表名,那你就需要做更多的工作。所以我建议你在迁移文件中搜索“old_table_name”,把找到的所有条目改成新的表名。例如,如果你之前使用的是Class Meta自定义表名,你可能会看到:

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

所以你需要把那个旧的表名改成新的。

现在你可以通过以下命令进行迁移:

python manage.py migrate xyz

到这一步,你的应用应该可以正常运行,因为你所做的只是更改了表名,并告诉Django去查找新的表名。

第二步是更改你的模型名称。这一步的难度主要取决于你的应用,但基本上你只需要把所有引用旧模型名称的代码改成引用新模型名称的代码。如果你在文件名和目录名中也用了旧模型名称来组织文件,可能还需要更改一些文件名和目录名。

完成这些后,你的应用应该可以正常运行。到这一步,你的任务基本上就完成了,应用应该可以正常使用新的模型名称和新的表名。你唯一会遇到的问题是,当你下次使用South的自动检测功能创建迁移时,它会尝试删除旧表并从头创建一个新表,因为它检测到了你的新模型名称。要解决这个问题,你需要创建另一个自定义迁移:

python manage.py schemamigration xyz tell_south_we_changed_the_model_name_for_old_model_name --empty

好在这里你什么都不用做,因为你已经更改了模型名称,所以South会自动识别。只需在迁移时用“pass”来进行前后迁移:

python manage.py migrate xyz

这样就不会做任何操作,South现在意识到它是最新的。试试:

python manage.py schemamigration xyz --auto

你应该会看到它检测到没有任何变化。

8

你可以仅仅使用 South 来完成这个操作。

在这个例子中,我有一个叫做 usergroups 的应用,它有以下模型:

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

我假设这个模型已经在 South 的迁移控制下了。

接下来,我们要改模型的名字:

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

然后从 South 创建一个空的迁移文件:

$ python manage.py schemamigration usergroups model_name_change --empty

这会为你创建一个迁移文件的框架,你可以在里面指定具体要做什么。如果我们把它编辑成这样(这个文件会在 app_name/migrations/ 文件夹里——在这个例子中是 usergroups/migrations/):

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']

forwards 方法里,我们把数据库表的名字改成新的模型名,这样 Django 的 ORM 就能找到它。我们在 backwards 方法里反向操作,以确保如果需要的话,可以撤销这个迁移。

运行迁移时,不需要导入或导出现有的数据:

$ python manage.py migrate

最后一步是更新那些引用 myUser_Group 的外键和多对多列,把它们改成引用 MyUserGroup。

撰写回答