Я пытался пройтись по решению, описанному T Stone, и, хотя я думаю, что это превосходный стартер и объясняет, как все должно быть сделано, я столкнулся с несколькими проблемами.
Я думаю, что в основном вам не нужно больше создавать запись таблицы для родительского класса, т. Е. Вам не нужно
new_movie.videofile_ptr = orm['media.VideoFile'].objects.create()
больше. Теперь Django сделает это автоматически для вас (если у вас есть ненулевые поля, вышеописанное не сработало для меня и выдало ошибку базы данных).
Я думаю, что это возможно из-за изменений в django и south, вот версия, которая работала для меня на ubuntu 10.10 с django 1.2.3 и south 0.7.1. Модели немного отличаются, но вы получите суть:
Начальная настройка
post1 / models.py:
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)
post2 / models.py:
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)
Очевидно, что есть много совпадений, поэтому я хотел бы учитывать общие черты
в общий пост модель и сохранить только различия в других
Модельные классы.
новая настройка:
genpost / models.py:
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)
post1 / models.py:
import genpost.models as gp
class SimplePost(gp.Post):
class Meta:
proxy = True
post2 / models.py:
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)
Если вы хотите последовать примеру, вам сначала нужно доставить эти модели на юг:
$./manage.py schemamigration post1 --initial
$./manage.py schemamigration post2 --initial
$./manage.py migrate
Перенос данных
Как это сделать? Сначала напишите новое приложение genpost и сделайте начальный
Миграции с юга:
$./manage.py schemamigration genpost --initial
(я использую $
для представления приглашения оболочки, поэтому не вводите его.)
Далее создайте новые классы SimplePost и ExtPost в post1 / models.py
и post2 / models.py соответственно (пока не удаляйте остальные классы).
Затем создайте схемы для этих двух типов:
$./manage.py schemamigration post1 --auto
$./manage.py schemamigration post2 --auto
Теперь мы можем применить все эти миграции:
$./manage.py migrate
Давайте рассмотрим суть вопроса, перенеся данные из post1 и post2 в genpost:
$./manage.py datamigration genpost post1_and_post2_to_genpost --freeze post1 --freeze post2
Затем отредактируйте genpost / migrations / 0002_post1_and_post2_to_genpost.py:
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.")
Теперь примените следующие миграции:
$./manage.py migrate
Затем вы можете удалить ненужные детали из post1 / models.py и post2 / models.py, а затем создать схемы для обновления таблиц до нового состояния:
$./manage.py schemamigration post1 --auto
$./manage.py schemamigration post2 --auto
$./manage.py migrate
И это должно быть! Надеюсь, все это работает, и вы провели рефакторинг своих моделей.