Я искал ответ на этот вопрос на сайте Юга, в Google и SO, но не мог найти простого способа сделать это.
Я хочу переименовать модель Django с помощью South. Допустим, у вас есть следующее:
class Foo(models.Model):
name = models.CharField()
class FooTwo(models.Model):
name = models.CharField()
foo = models.ForeignKey(Foo)
и вы хотите преобразовать Foo в Bar, а именно
class Bar(models.Model):
name = models.CharField()
class FooTwo(models.Model):
name = models.CharField()
foo = models.ForeignKey(Bar)
Чтобы не усложнять, я просто пытаюсь изменить имя с Foo
на Bar
, но пока игнорирую foo
члена FooTwo
.
Как проще всего это сделать, используя Юг?
- Возможно, я мог бы выполнить миграцию данных, но это кажется довольно сложным.
- Напишите, например
db.rename_table('city_citystate', 'geo_citystate')
, настраиваемую миграцию, но я не уверен, как исправить внешний ключ в этом случае. - Более простой способ, который вы знаете?
Ответы:
Чтобы ответить на ваш первый вопрос, простое переименование модели / таблицы довольно просто. Выполните команду:
(Обновление 2: попробуйте
--auto
вместо того,--empty
чтобы избежать предупреждения ниже. Спасибо @KFB за подсказку.)Если вы используете старую версию south, вам понадобится
startmigration
вместоschemamigration
.Затем вручную отредактируйте файл миграции, чтобы он выглядел так:
class Migration(SchemaMigration): def forwards(self, orm): db.rename_table('yourapp_foo', 'yourapp_bar') def backwards(self, orm): db.rename_table('yourapp_bar','yourapp_foo')
Вы можете сделать это проще, используя
db_table
опцию Meta в вашем классе модели. Но каждый раз, когда вы это делаете, вы увеличиваете унаследованный вес своей кодовой базы - если имена классов отличаются от имен таблиц, ваш код сложнее понимать и поддерживать. Для ясности я полностью поддерживаю такие простые рефакторинги.(обновление) Я только что попробовал это в производственной среде и получил странное предупреждение, когда пошел применять миграцию. Он сказал:
Я ответил «нет», и вроде бы все нормально.
источник
Внесите изменения
models.py
и запуститеКогда вы проверите файл миграции, вы увидите, что он удаляет таблицу и создает новую.
class Migration(SchemaMigration): def forwards(self, orm): # Deleting model 'Foo' db.delete_table('myapp_foo') # Adding model 'Bar' db.create_table('myapp_bar', ( ... )) db.send_create_signal('myapp', ['Bar']) def backwards(self, orm): ...
Это не совсем то, что вам нужно. Вместо этого отредактируйте миграцию так, чтобы она выглядела так:
class Migration(SchemaMigration): def forwards(self, orm): # Renaming model from 'Foo' to 'Bar' db.rename_table('myapp_foo', 'myapp_bar') if not db.dry_run: orm['contenttypes.contenttype'].objects.filter( app_label='myapp', model='foo').update(model='bar') def backwards(self, orm): # Renaming model from 'Bar' to 'Foo' db.rename_table('myapp_bar', 'myapp_foo') if not db.dry_run: orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo')
В случае отсутствия
update
оператораdb.send_create_signal
вызов создаст новыйContentType
с новым названием модели. Но лучше использоватьupdate
тот,ContentType
который у вас уже есть, если на него указывают объекты базы данных (например, через aGenericForeignKey
).Кроме того, если вы переименовали некоторые столбцы, которые являются внешними ключами переименованной модели, не забудьте
источник
contenttypes.ContentType
модель к замороженным моделям с помощью--frozen
флага./manage.py datamigration
. Например:./manage.py datamigration --frozen contenttypes myapp update_contenttypes
. Затем отредактируйте myapp_migrations / NNNN_update_contenttypes.py, указав код обновления типа контента, как указано выше.Юг не может этого сделать сам - откуда он знает, что
Bar
представляет то, чтоFoo
раньше? Я бы написал для этого специальную миграцию. Вы можете изменить свойForeignKey
код, как вы это делали выше, а затем просто переименовать соответствующие поля и таблицы, что вы можете делать как хотите.Наконец, действительно ли вам нужно это делать? Мне еще не нужно было переименовывать модели - названия моделей - это всего лишь деталь реализации, особенно с учетом наличия
verbose_name
опции Meta.источник
db_table
опцию Meta, чтобы имя таблицы базы данных оставалось прежним.db_table
вы, используется ли он для получения имен внешних ключей?Я следил за решением Леопда выше. Но это не повлияло на названия моделей. Я вручную изменил его в коде (также в связанных моделях, где это называется FK). И сделал еще одну миграцию на юг, но с параметром --fake. Это делает имена моделей и имена таблиц одинаковыми.
Только что осознал, что можно сначала начать с изменения названий моделей, а затем отредактировать файл миграции перед их применением. Намного чище.
источник