Check out response below by Paul for some notes on compatibility with newer versions of Django/South.个
这似乎是一个有趣的问题,我正在成为南方的铁杆粉丝,所以我决定稍微研究一下.我在您上面描述的抽象的基础上构建了一个测试项目,并且已经成功地使用South执行了您所询问的migrations.在我们讨论代码之前,有几个注意事项:
South文档建议分别进行模式迁移和数据migrations.在这件事上我也跟着做了.
在后端,Django通过在继承模型上自动创建ONEtoONE字段来表示继承表
理解了这一点,我们的南方迁移需要手动正确地处理ONEtoONE字段,然而,在实验中,南方(或者Django本身)似乎不能在多个同名的继承表上创建ONEtoONE文件.正因为如此,我重命名了电影/电视应用程序中的每个子表,使其与其自己的应用程序(即.MovieVideoFile/ShowVideoFile).
在使用实际的数据迁移代码时,South似乎更喜欢首先创建ONEtoONE字段,然后将数据分配给它.在创建期间将数据分配给ONEtoONE字段会导致SOUTH阻塞.(对于南方所有的凉爽来说,这是一个公平的妥协).
所以说了这些之后,我试着记录下发出的控制台命令.必要时我会插入 comments .最后的代码在底部.
命令历史记录
django-admin.py startproject southtest
manage.py startapp movies
manage.py startapp tv
manage.py syncdb
manage.py startmigration movies --initial
manage.py startmigration tv --initial
manage.py migrate
manage.py shell # added some fake data...
manage.py startapp media
manage.py startmigration media --initial
manage.py migrate
# edited code, wrote new models, but left old ones intact
manage.py startmigration movies unified-videofile --auto
# create a new (blank) migration to hand-write data migration
manage.py startmigration movies videofile-to-movievideofile-data
manage.py migrate
# edited code, wrote new models, but left old ones intact
manage.py startmigration tv unified-videofile --auto
# create a new (blank) migration to hand-write data migration
manage.py startmigration tv videofile-to-movievideofile-data
manage.py migrate
# removed old VideoFile model from apps
manage.py startmigration movies removed-videofile --auto
manage.py startmigration tv removed-videofile --auto
manage.py migrate
出于空间考虑,因为模型最终看起来总是一样的,所以我只打算用"电影"应用程序进行演示.
电影/模型.py
from django.db import models
from media.models import VideoFile as BaseVideoFile
# This model remains until the last migration, which deletes
# it from the schema. Note the name conflict with media.models
class VideoFile(models.Model):
movie = models.ForeignKey(Movie, blank=True, null=True)
name = models.CharField(max_length=1024, blank=True)
size = models.IntegerField(blank=True, null=True)
ctime = models.DateTimeField(blank=True, null=True)
class MovieVideoFile(BaseVideoFile):
movie = models.ForeignKey(Movie, blank=True, null=True, related_name='shows')
电影/迁移/0002_统一视频文件.py(模式迁移)
from south.db import db
from django.db import models
from movies.models import *
class Migration:
def forwards(self, orm):
# Adding model 'MovieVideoFile'
db.create_table('movies_movievideofile', (
('videofile_ptr', orm['movies.movievideofile:videofile_ptr']),
('movie', orm['movies.movievideofile:movie']),
))
db.send_create_signal('movies', ['MovieVideoFile'])
def backwards(self, orm):
# Deleting model 'MovieVideoFile'
db.delete_table('movies_movievideofile')
movies/migration/0003_videofile-to-movievideofile-data.py(数据迁移)
from south.db import db
from django.db import models
from movies.models import *
class Migration:
def forwards(self, orm):
for movie in orm['movies.videofile'].objects.all():
new_movie = orm.MovieVideoFile.objects.create(movie = movie.movie,)
new_movie.videofile_ptr = orm['media.VideoFile'].objects.create()
# videofile_ptr must be created first before values can be assigned
new_movie.videofile_ptr.name = movie.name
new_movie.videofile_ptr.size = movie.size
new_movie.videofile_ptr.ctime = movie.ctime
new_movie.videofile_ptr.save()
def backwards(self, orm):
print 'No Backwards'
南方太棒了!
OK标准免责声明:您正在处理实时数据.我在这里给了您工作代码,但是请使用--db-dry-run
来测试您的模式.在try 任何事情之前,始终要做好备份,并且通常要小心.
COMPATIBILITY NOTICE个
我将保持我的原始消息不变,但是South已经将命令manage.py startmigration
改为manage.py schemamigration
.