<p>我确实尝试过T斯通提出的解决方案,虽然我认为这是一个极好的开端,并解释了应该如何做,但我遇到了一些问题。</p>
<p>我认为大多数情况下,您不需要再为父类创建表条目,也就是说,您不需要</p>
<pre><code>new_movie.videofile_ptr = orm['media.VideoFile'].objects.create()
</code></pre>
<p>再也没有了。Django现在将自动为您执行此操作(如果您有非空字段,则上述操作对我不起作用,并给了我一个数据库错误)。</p>
<p>我认为这可能是由于django和south的变化,这里有一个版本在ubuntu 10.10和django 1.2.3以及south 0.7.1上对我有效。模型有点不同,但你会得到要点:</p>
<h3>初始设置</h3>
<p><strong>post1/models.py:</strong></p>
<pre><code>class Author(models.Model):
first = models.CharField(max_length=30)
last = models.CharField(max_length=30)
class Tag(models.Model):
name = models.CharField(max_length=30, primary_key=True)
class Post(models.Model):
created_on = models.DateTimeField()
author = models.ForeignKey(Author)
tags = models.ManyToManyField(Tag)
title = models.CharField(max_length=128, blank=True)
content = models.TextField(blank=True)
</code></pre>
<p><strong>post2/models.py:</strong></p>
<pre><code>class Author(models.Model):
first = models.CharField(max_length=30)
middle = models.CharField(max_length=30)
last = models.CharField(max_length=30)
class Tag(models.Model):
name = models.CharField(max_length=30)
class Category(models.Model):
name = models.CharField(max_length=30)
class Post(models.Model):
created_on = models.DateTimeField()
author = models.ForeignKey(Author)
tags = models.ManyToManyField(Tag)
title = models.CharField(max_length=128, blank=True)
content = models.TextField(blank=True)
extra_content = models.TextField(blank=True)
category = models.ForeignKey(Category)
</code></pre>
<p>很明显有很多重叠,所以我想把共性考虑进去
变成一个普通的post</em>模型
模型类。</p>
<p>新设置:</p>
<p><strong>genpost/models.py:</strong></p>
<pre><code>class Author(models.Model):
first = models.CharField(max_length=30)
middle = models.CharField(max_length=30, blank=True)
last = models.CharField(max_length=30)
class Tag(models.Model):
name = models.CharField(max_length=30, primary_key=True)
class Post(models.Model):
created_on = models.DateTimeField()
author = models.ForeignKey(Author)
tags = models.ManyToManyField(Tag)
title = models.CharField(max_length=128, blank=True)
content = models.TextField(blank=True)
</code></pre>
<p><strong>post1/models.py:</strong></p>
<pre><code>import genpost.models as gp
class SimplePost(gp.Post):
class Meta:
proxy = True
</code></pre>
<p><strong>post2/models.py:</strong></p>
<pre><code>import genpost.models as gp
class Category(models.Model):
name = models.CharField(max_length=30)
class ExtPost(gp.Post):
extra_content = models.TextField(blank=True)
category = models.ForeignKey(Category)
</code></pre>
<p>如果你想继续,你首先需要把这些模型带到南方:</p>
<pre><code>$./manage.py schemamigration post1 --initial
$./manage.py schemamigration post2 --initial
$./manage.py migrate
</code></pre>
<h3>迁移数据</h3>
<p>怎么办?首先编写新的应用程序genpost并执行
南迁:</p>
<pre><code>$./manage.py schemamigration genpost --initial
</code></pre>
<p>(我使用<code>$</code>来表示shell提示符,所以不要键入它。)</p>
<p>接下来在post1/models.py中创建新的类<em>SimplePost</em>和<em>ExtPost</em>
分别是post2/models.py(不要删除其他类)。
然后为这两个创建计划:</p>
<pre><code>$./manage.py schemamigration post1 --auto
$./manage.py schemamigration post2 --auto
</code></pre>
<p>现在我们可以应用所有这些迁移:</p>
<pre><code>$./manage.py migrate
</code></pre>
<p>让我们进入问题的核心,将数据从post1和post2迁移到genpost:</p>
<pre><code>$./manage.py datamigration genpost post1_and_post2_to_genpost --freeze post1 --freeze post2
</code></pre>
<p>然后将genpost/migrations/0002_post1_和_post2_编辑为_genpost.py:</p>
<pre><code>class Migration(DataMigration):
def forwards(self, orm):
#
# Migrate common data into the new genpost models
#
for auth1 in orm['post1.author'].objects.all():
new_auth = orm.Author()
new_auth.first = auth1.first
new_auth.last = auth1.last
new_auth.save()
for auth2 in orm['post2.author'].objects.all():
new_auth = orm.Author()
new_auth.first = auth2.first
new_auth.middle = auth2.middle
new_auth.last = auth2.last
new_auth.save()
for tag in orm['post1.tag'].objects.all():
new_tag = orm.Tag()
new_tag.name = tag.name
new_tag.save()
for tag in orm['post2.tag'].objects.all():
new_tag = orm.Tag()
new_tag.name = tag.name
new_tag.save()
for post1 in orm['post1.post'].objects.all():
new_genpost = orm.Post()
# Content
new_genpost.created_on = post1.created_on
new_genpost.title = post1.title
new_genpost.content = post1.content
# Foreign keys
new_genpost.author = orm['genpost.author'].objects.filter(\
first=post1.author.first,last=post1.author.last)[0]
new_genpost.save() # Needed for M2M updates
for tag in post1.tags.all():
new_genpost.tags.add(\
orm['genpost.tag'].objects.get(name=tag.name))
new_genpost.save()
post1.delete()
for post2 in orm['post2.post'].objects.all():
new_extpost = p2.ExtPost()
new_extpost.created_on = post2.created_on
new_extpost.title = post2.title
new_extpost.content = post2.content
# Foreign keys
new_extpost.author_id = orm['genpost.author'].objects.filter(\
first=post2.author.first,\
middle=post2.author.middle,\
last=post2.author.last)[0].id
new_extpost.extra_content = post2.extra_content
new_extpost.category_id = post2.category_id
# M2M fields
new_extpost.save()
for tag in post2.tags.all():
new_extpost.tags.add(tag.name) # name is primary key
new_extpost.save()
post2.delete()
# Get rid of author and tags in post1 and post2
orm['post1.author'].objects.all().delete()
orm['post1.tag'].objects.all().delete()
orm['post2.author'].objects.all().delete()
orm['post2.tag'].objects.all().delete()
def backwards(self, orm):
raise RuntimeError("No backwards.")
</code></pre>
<p>现在应用这些迁移:</p>
<pre><code>$./manage.py migrate
</code></pre>
<p>接下来,可以从post1/models.py和post2/models.py中删除现在冗余的部分,然后创建schemamigrations以将表更新为新状态:</p>
<pre><code>$./manage.py schemamigration post1 --auto
$./manage.py schemamigration post2 --auto
$./manage.py migrate
</code></pre>
<p>应该就是这样!希望这一切都能奏效,你已经重构了你的模型。</p>