可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am renaming an application to a more suitable name. In doing so, I want to ensure that South properly migrates the database (renames database tables and changes references in django_content_type or south_migrationhistory). I know how to migrate a model to a different app, but when I try rename the app itself, South does not recognize the migration history properly.
Undesirable solution: In renaming old_app
to new_app
I could leave old_app/migrations
intact and add new migrations to this directory to migrate the database to reference new_app
.
If possible I would prefer to delete the directory old_app
entirely. I have not yet thought of a better solution to this problem.
What is the best way to rename an app with Django South without losing data?
回答1:
I agree with Laksham that you should avoid this situation. But sometimes, we have to. I've faced this situation in the past and I've managed it this way.
If you want to avoid losing data you can dump the old application data into a json file.
python manage.py dumpdata old_app --natural --indent=4 1> old_app.json
Note the --natural option that will force the content types to be exported with their natural keys (app_name, model)
Then you can create a small command to open this json file and to replace all the old_app references with the new_app.
Something like this should work
class Command(BaseCommand):
help = u"Rename app in json dump"
def handle(self, *args, **options):
try:
old_app = args[0]
new_app = args[1]
filename = args[2]
except IndexError:
print u'usage :', __name__.split('.')[-1], 'old_app new_app dumpfile.json'
return
try:
dump_file = open(filename, 'r')
except IOError:
print filename, u"doesn't exist"
return
objects = json.loads(dump_file.read())
dump_file.close()
for obj in objects:
obj["model"] = obj["model"].replace(old_app, new_app, 1)
if obj["fields"].has_key("content_type") and (old_app == obj["fields"]["content_type"][0]):
obj["fields"]["content_type"][0] = new_app
dump_file = open(filename, 'w')
dump_file.write(json.dumps(objects, indent=4))
dump_file.close()
Then rename the application, change the name in INSTALLED_APPS.
Then, you should remove all south migrations, regenerate and apply an initial migration for the new app. Then run the SQL command:
update django_content_type set app_label='new_app' where app_label='old_app'
Then launch a south migrate for the new app in order to create the tables and load the json file.
python manage.py loaddata old_app.json
I've done something similar on a project and it seems to work ok.
I hope it helps
回答2:
It is possible to rename an app.
As example project, see:
https://github.com/ASKBOT/django-south-app-rename-example
Basically, there are 2 migrations. First the tables are renamed using a db.rename_table()
, and next the content types are updated.
This can be combined into one migration by checking for if not db.dry_run:
. See How do I migrate a model out of one django app and into a new one? for an example of that.
For a initial migrations, you can directly rename the existing tables, if they are there:
if 'old_app_table_name' in connection.introspection.table_names():
db.rename_table('old_app_table_name', 'new_app_table_name')
else:
# Create new app tables directly.
For tables with more migrations, you may need to check whether the old migration name was already applied:
from south.models import MigrationHistory
if MigrationHistory.objects.exists(app_name='old_app', migration='0001_initial'):
return
Lastly, I recommend using an IDE (e.g. a PyCharm trial) to rename the package (right click, refactor -> rename on the package) because it will update all usages across the application for you, including the URLconf, settings and imports.
回答3:
After some plugging away, I came up with this. Should take care of it.
https://gist.github.com/jamesmfriedman/6168003
回答4:
Disclaimer: This answer is for those who do not care about migration history and have already messed up by renaming the app, completely forgetting about migrations (like I did).
Worked for me.
After changing folder name, dealing with all imports in your code and changing corresponding app name in settings.INSTALLED_APPS, just delete all previous migrations folder. Then make an initial one like this
manage.py schemamigration new_app --initial
Then, when applying it, fake it like this
manage.py migrate new_app 0001 --fake
Do not forget to --fake it, otherwise you might end up losing data
All further migrations will work just fine
manage.py migrate new_app 0002
Also you can delete from south_migrationhistory where app_name = "old_app"
回答5:
I wouldn't mess with the app names. You refer to the app names literally everywhere. URL confs, settings, other apps, templates etc.
The way django is designed, correspondingly south, assumes there is no need to change the app names. - name your projects what you want. You don't refer to it anywhere. Changing app names is cumbersome. Your undesirable solution is the best solution I see, if you really want to rename your app.
For what it is worth, you can always use the python import as
to import the app in a different name, if you so desire.