Я искал ответ на это на сайте South, Google и SO, но не смог найти простой способ сделать это.
Я хочу переименовать модель Django, используя Юг. Скажем, у вас есть следующее:
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')
, но я не уверен, как исправить внешний ключ в этом случае.Чтобы ответить на ваш первый вопрос, простое переименование модели/таблицы довольно просто. Выполните команду:
./manage.py schemamigration yourapp rename_foo_to_bar --empty
(Обновление 2: попробуйте --auto
вместо --empty
, чтобы избежать предупреждения ниже. Благодаря @KFB для подсказки.)
Если вы используете более старую версию юга, вам понадобится 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 в классе модели. Но каждый раз, когда вы это делаете, вы увеличиваете унаследованный вес вашей кодовой базы - если имена классов отличаются от имен таблиц, ваш код становится сложнее понять и поддерживать. Я полностью поддерживаю выполнение простых рефакторингов, подобных этому, для ясности.
(обновление) Я просто попробовал это на производстве и получил странное предупреждение, когда я пошел применять миграцию. Он сказал:
The following content types are stale and need to be deleted: yourapp | foo Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you're unsure, answer 'no'.
Я ответил "нет", и все было в порядке.
Внесите изменения в models.py
, а затем запустите
./manage.py schemamigration --auto myapp
Когда вы проверяете файл миграции, вы увидите, что он удаляет таблицу и создает новую.
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
у вас уже есть, если есть объекты базы данных, указывающие на него (например, через GenericForeignKey
).
Кроме того, если вы переименовали некоторые столбцы, которые являются внешними ключами для переименованной модели, не забудьте
db.rename_column(myapp_model, foo_id, bar_id)
Юг не может сделать это сам - откуда он знает, что Bar
представляет, к чему привык Foo
? Это то, что я написал для пользовательской миграции. Вы можете изменить свой ForeignKey
в коде, как вы это делали выше, а затем просто переименовать соответствующие поля и таблицы, которые вы можете сделать любым способом.
Наконец, вам действительно нужно это сделать? Мне еще не нужно переименовывать модели. Имена моделей - это всего лишь детализация реализации, особенно учитывая наличие опции verbose_name
Meta.
db_table
чтобы имя таблицы базы данных db_table
прежним.
db_table
используется для получения имен внешних ключей?
Я следовал за решением Leopd выше. Но это не изменило названия моделей. Я изменил его вручную в коде (также в связанных моделях, где это называется FK). И сделал еще одну южную миграцию, но с опцией --fake. Это делает имена моделей и имена таблиц одинаковыми.
Только что понятый, можно сначала начать с изменения имен моделей, а затем отредактировать файл миграции перед их применением. Гораздо чище.