Стратегия миграции Django для переименования полей модели и отношений
я планирую переименовать несколько моделей в существующем проекте Django, где есть много других моделей, которые имеют отношения внешнего ключа к моделям, которые я хотел бы переименовать. Я уверен, что для этого потребуется несколько миграций, но я не уверен в точной процедуре.
предположим, я начинаю со следующих моделей в приложении Django под названием myapp
:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
я хочу переименовать Foo
модель, потому что имя на самом деле не делает смысл и вызывает путаницу в коде, и Bar
сделал бы для гораздо более ясного имени.
из того, что я прочитал в документации по разработке Django, я предполагаю следующую стратегию миграции:
Шаг 1
изменить models.py
:
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_ridonkulous = models.BooleanField()
Примечание AnotherModel
имя поля для foo
не изменяется, но отношение обновляется до Bar
модель. Мои рассуждения таковы, что я не должен меняться слишком сильно сразу и что если я изменено имя этого поля на bar
я бы рискнул потерять данные в этой колонке.
Шаг 2
создать пустую миграцию:
python manage.py makemigrations --empty myapp
Шаг 3
редактировать Migration
класс в файле миграции, созданном на Шаге 2, чтобы добавить RenameModel
операция в списке операций:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
Шаг 4
применить миграции:
python manage.py migrate
Шаг 5
измените связанные имена полей в models.py
:
class Bar(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_ridonkulous = models.BooleanField()
Шаг 6
создайте еще одну пустую миграцию:
python manage.py makemigrations --empty myapp
Шаг 7
редактировать Migration
класс в файле миграции, созданном на шаге 6, чтобы добавить RenameField
Операция(Ы) для любых связанных имен полей в списке операций:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_rename_fields'), # <-- is this okay?
]
operations = [
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Шаг 8
применить 2-ой миграции:
python manage.py migrate
помимо обновления остальной части кода (представления, формы и т. д.) отражать новые имена переменных, это в основном, как новая функциональность миграции будет работать?
кроме того, это похоже на много шагов. Можно ли каким-то образом сократить миграционные операции?
спасибо!
10 ответов
поэтому, когда я попробовал это, кажется, вы можете конденсировать Шаг 3-7:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar'),
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Вы можете получить некоторые ошибки, если вы не обновляете имена, где он импортируется, например admin.py и даже более старые файлы миграции (!).
обновление: As ceasaro упоминает, более новые версии Django обычно могут обнаружить и спросить, переименована ли модель. Так что попробуйте manage.py makemigrations
сначала проверьте файл миграции.
сначала я думал, что метод Fiver работает для меня, потому что миграция работала хорошо до шага 4. Однако неявные изменения "ForeignKeyField(Foo)" в "ForeignKeyField (Bar)" не были связаны ни с какими миграциями. Вот почему миграция не удалась, когда я хотел переименовать поля отношений (шаг 5-8). Это может быть связано с тем, что мои "AnotherModel" и "YetAnotherModel" отправляются в других приложениях в моем случае.
поэтому мне удалось переименовать мои модели и отношения поля, выполняющие следующие действия:
я адаптировал метод из этой и особенно трюк otranzer.
так как пятерка, скажем, у нас есть в myapp:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
и myotherapp:
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
Шаг 1:
преобразуйте каждое OntToOneField(Foo) или ForeignKeyField (Foo) в IntegerField (). (Это сохранит идентификатор связанного объекта Foo в качестве значения из integerfield).
class AnotherModel(models.Model):
foo = models.IntegerField()
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.IntegerField()
is_ridonkulous = models.BooleanField()
затем
python manage.py makemigrations
python manage.py migrate
Шаг 2: (например, шаг 2-4 от Fiver)
изменить название модели
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
создать пустую миграцию:
python manage.py makemigrations --empty myapp
затем отредактируйте его так:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
в конце концов
python manage.py migrate
Шаг 3:
преобразуйте свое целочисленное поле() в их предыдущее ForeignKeyField, OneToOneField, но с помощью новая модель бара. (Предыдущее целочисленное поле хранило идентификатор, поэтому django понял это и восстановил соединение, что круто.)
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar)
is_ridonkulous = models.BooleanField()
затем выполните:
python manage.py makemigrations
очень важно, что на этом шаге вы должны изменить все новые миграции и добавить зависимость от RenameModel Foo-> Bar миграции. Так что если оба AnotherModel и YetAnotherModel в myotherapp созданный миграции в myotherapp должны выглядеть это:
class Migration(migrations.Migration):
dependencies = [
('myapp', '00XX_the_migration_of_myapp_with_renamemodel_foo_bar'),
('myotherapp', '00xx_the_migration_of_myotherapp_with_integerfield'),
]
operations = [
migrations.AlterField(
model_name='anothermodel',
name='foo',
field=models.ForeignKey(to='myapp.Bar'),
),
migrations.AlterField(
model_name='yetanothermodel',
name='foo',
field=models.ForeignKey(to='myapp.Bar')
),
]
затем
python manage.py migrate
Шаг 4:
в конечном итоге вы можете переименовать свои поля
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) <------- Renamed fields
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) <------- Renamed fields
is_ridonkulous = models.BooleanField()
а затем сделайте автоматическое переименование
python manage.py makemigrations
(django должен спросить вас, действительно ли вы переименовали modelname, скажите "да")
python manage.py migrate
и это все!
это работает на Django1.8
Мне нужно сделать то же самое. Я изменил модель сразу (т. е. Шаг 1 и Шаг 5 вместе). Затем создал миграцию схемы, но отредактировал ее так:
class Migration(SchemaMigration):
def forwards(self, orm):
db.rename_table('Foo','Bar')
def backwards(self, orm):
db.rename_table('Bar','Foo')
Это прекрасно работало. Все мои существующие данные появились, все остальные таблицы ссылались на Bar fine.
отсюда:https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
для Django 1.10 мне удалось изменить два имени класса модели (включая ForeignKey и с данными), просто запустив Makemigrations, а затем мигрировать для приложения. Для шага Makemigrations мне пришлось подтвердить, что я хочу изменить имена таблиц. Migrate без проблем изменил имена таблиц.
затем я изменил имя поля ForeignKey на соответствующее, и снова Makemigrations попросили подтвердить, что я хочу изменить имя. Миграции, чем сделать изменения.
поэтому я сделал это в два шага без специального редактирования файлов. Сначала я получил ошибки, потому что забыл изменить admin.py файл, как упоминалось @wasibigeek.
Шаг 1: измените связанные имена полей в models.py
class Bar(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_ridonkulous = models.BooleanField()
Шаг 2: Создайте пустую миграцию
python manage.py makemigrations --empty myapp
Шаг 3: отредактируйте класс миграции в миграция файл, созданный на Шаге 2
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='AnotherModel',
name='foo',
field=models.IntegerField(),
),
migrations.AlterField(
model_name='YetAnotherModel',
name='foo',
field=models.IntegerField(),
),
migrations.RenameModel('Foo', 'Bar'),
migrations.AlterField(
model_name='AnotherModel',
name='foo',
field=models.ForeignKey(to='myapp.Bar'),
),
migrations.AlterField(
model_name='YetAnotherModel',
name='foo',
field=models.ForeignKey(to='myapp.Bar'),
),
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Шаг 4: Примените миграцию
python manage.py migrate
сделал
P. S. Я пробовал такой подход на Django 1.9
я использую Django версии 1.9.4
Я должен выполнить следующие шаги: -
Я просто переименовал модель oldName в NewName
Запустить python manage.py makemigrations
. Он попросит вас
Did you rename the appname.oldName model to NewName? [y/N]
выберите Y
Run python manage.py migrate
и он попросит вас
следующие типы контента являются устаревшими и должны быть удалены:
appname | oldName
appname | NewName
любые объекты, связанные с этими типами контента внешним ключом будет также исключить. Вы уверены, что хотите удалить эти типы контента? Если вы не уверены, ответьте "нет".
Type 'yes' to continue, or 'no' to cancel: Select No
он переименовывает и переносит все существующие данные в новую именованную таблицу для меня.
к сожалению, я нашел проблемы (каждый django 1.x) с переименованием миграции, которые оставляют старые имена таблиц в БД (даже не пытайтесь ничего на старой таблице, просто переименуйте модель).
решение для этого случая:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
...
Bar = Foo
мне нужно было переименовать пару таблиц. Но только одно переименование модели было замечено Django. Это произошло потому, что Django перебирает добавленные, а затем удаленные модели. Для каждой пары он проверяет, являются ли они одним и тем же приложением и имеют идентичные поля. Только одна таблица не имела внешних ключей к таблицам для переименования (внешние ключи содержат имя класса модели, как вы помните). Другими словами, только в одной таблице не было изменений полей. Вот почему это было замечено.
Итак, решение чтобы переименовать одну таблицу за раз, измените имя класса модели в models.py
, возможно views.py
, и совершая миграции. После этого проверьте код на наличие других ссылок (имена классов моделей, связанные (запросы) имена, имена переменных). При необходимости сделайте миграцию. Затем при необходимости объедините все эти миграции в одну (убедитесь, что вы также скопировали импорт).
Я бы сделал @ceasaro слова, Мои на его комментарий по этому ответ.
новые версии Django могут обнаруживать изменения и спрашивать о том, что было сделано. Я также добавил бы, что Django может смешивать порядок выполнения некоторых команд миграции.
было бы разумно применить небольшие изменения и запустить makemigrations
и migrate
и если ошибка возникает, файл миграции можно редактировать.
некоторые строки порядок выполнения можно изменить, чтобы избежать и омеги.
я обновил Django с версии 10 до версии 11:
sudo pip install -U Django
(-U
для "апгрейда") и это решило проблему.