<p><strong>查看以下Paul的回复,了解有关与Django/South新版本兼容的一些注意事项。</strong></p>
<hr/>
<p>这似乎是一个有趣的问题,我正在成为一个南方的大粉丝,所以我决定调查一下。我在上面描述的抽象基础上构建了一个测试项目,并成功地使用South执行了您所要求的迁移。在我们开始代码之前,这里有几个注意事项:</p>
<ul>
<li><p>South文档建议分别执行模式迁移和数据迁移。我也跟着做了。</p></li>
<li><p>在后端,Django通过在继承模型上自动创建OneToOne字段来表示继承的表</p></li>
<li><p>了解到这一点,我们的South迁移需要手动正确处理OneToOne字段,然而,在实验中,South(或者Django本身)似乎无法在多个同名继承表上创建OneToOne字段。因此,我将movies/tv应用程序中的每个子表重命名为各自的应用程序(即MovieVideoFile/ShowVideoFile)。</p></li>
<li><p>在处理实际的数据迁移代码时,South似乎更喜欢先创建OneToOne字段,然后将数据分配给它。在创建期间将数据分配给OneToOne字段会导致South阻塞。(一个公平的妥协,所有的凉爽是南方)。</p></li>
</ul>
<p>所以说了这么多,我试着记录下正在发出的控制台命令。必要时我会插一句评论。最后的代码在底部。</p>
<h2>命令历史记录</h2>
<pre><code>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
</code></pre>
<p>为了节省空间,而且由于模型最终看起来总是一样的,我只想用“电影”应用程序演示一下。</p>
<h2>电影/模型.py</h2>
<pre><code>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')
</code></pre>
<h2>movies/migrations/0002_unified-videofile.py(架构迁移)</h2>
<pre><code>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')
</code></pre>
<h2>movies/migration/0003_videofile-to-movievideofile-data.py(数据迁移)</h2>
<pre><code>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'
</code></pre>
<h2>南方太棒了!</h2>
<p>好的,标准免责声明:你在处理实时数据。我已经给了您工作代码,但是请使用<code>--db-dry-run</code>来测试您的模式。在尝试任何事情之前都要做备份,通常要小心。</p>
<p><strong>兼容性注意事项</strong></p>
<p>我将保持原始消息的完整性,但是South已经将命令<code>manage.py startmigration</code>更改为<code>manage.py schemamigration</code>。</p>