Перенос данных из "Много-ко-многим" в "Много-ко-многим через" в джанго
У меня есть модель
class Category(models.Model):
title = models.CharField(...)
entry = models.ManyToManyField(Entry,null=True,blank=True,
related_name='category_entries',
)
Я хочу реорганизовать дополнительные данные с каждой связью:
class Category(models.Model):
title = models.CharField(...)
entry = models.ManyToManyField(Entry,null=True,blank=True,
related_name='category_entries',
through='CategoryEntry',
)
Но юг удаляет существующую таблицу. Как я могу сохранить существующие отношения m-t-m?
Ответы
Ответ 1
-
Создайте промежуточную модель без каких-либо дополнительных полей. Дайте ему уникальное ограничение для соответствия существующему и укажите имя таблицы в соответствии с существующим:
class CategoryEntry(models.Model):
category = models.ForeignKey(Category)
entry = models.ForeignKey(Entry)
class Meta:
db_table='main_category_entries' #change main_ to your application
unique_together = (('category', 'entry'))
-
Запустите миграцию схемы юга.
-
Отредактируйте сгенерированную миграцию схемы script и закомментируйте все записи вперед и назад, так как вы будете повторно использовать существующую таблицу пересечений. Добавьте pass
, чтобы завершить методы.
-
Запустите миграцию.
-
Обновить любой существующий код. Как говорится в https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships, "В отличие от обычных полей" много-ко-многим "вы не можете использовать add, create или assign для создания отношений", поэтому вам нужно будет изменить любой существующий код приложения, например
c.entry.add(e)
может стать:
try:
categoryentry = c.categoryentry_set.get(entry = e)
except CategoryEntry.DoesNotExist:
categoryentry = CategoryEntry(category=c, entry=e)
categoryentry.save()
и
e.category_entries.add(c)
может стать:
categoryentry = CategoryEntry(category=c, entry=e) #set extra fields here
categoryentry.save()
и
c.entry.remove(e)
может стать:
categoryentry = c.categoryentry_set.get(entry = e)
categoryentry.delete()
-
Как только эта начальная псевдо-миграция была выполнена, вы должны затем добавить дополнительные поля в CategoryEntry
и создать дополнительные миграции как обычно.
Ответ 2
У меня была эта проблема в Django 1.7+, где миграции были частью ядра Django, после некоторых исследований мне удалось ее решить. В случае, если у кого-то есть проблемы, это решение:
Так как состояние "кода" базы данных обрабатывается по-разному на юге (полное состояние сохраняется при каждой миграции), а Django 1.7 (он рассчитывается из всех миграций), вам нужно указать code_state в Django, что модель имеет был добавлен, хотя он этого не сделал.
Как и выше, это нужно сделать в несколько шагов.
-
Создайте промежуточную модель, как в приведенном выше ответе:
class CategoryEntry(models.Model):
category = models.ForeignKey(Category)
entry = models.ForeignKey(Entry)
class Meta:
db_table='main_category_entries' #change main_ to your application
unique_together = (('category', 'entry'))
-
Создайте автоматизацию и измените код. Заменить список операций списком с помощью одного
migrations.SeparateDatabaseAndState(database_operations, state_operations)
с списком автогенерированных операций как аргумент state_operations
и с пустым списком database_operations. Он будет выглядеть так:
class Migration(migrations.Migration):
operations = [
migrations.SeparateDatabaseAndState(
state_operations = [ <original operations list> ],
database_operations= []
),
]
-
Отредактируйте CategoryEntry, чтобы содержать то, что вы хотите, и создайте новую автоматизацию.
Ответ 3
Я бы сделал это следующим образом:
-
Добавить класс CategoryEntry в модель и выполнить миграцию автоматической схемы. Это добавит пустую таблицу, содержащую свойства "CategoryEntry". Следует отметить, что старая таблица M2M остается нетронутой, так как "through =" CategoryEntry "еще не добавлено.
-
Проведите миграцию данных, чтобы скопировать все данные из существующей таблицы M2M в таблицу, созданную на шаге 1. Для этого запустите команду datamigration и измените методы forward() и backward() в автоматически сгенерированном миграция script соответственно.
-
Теперь добавьте часть = 'CategoryEntry' (именно так, как вы хотели) и выполните схему. это снизит старую таблицу M2M.
Надеюсь, это поможет. Удачи...