Самый простой способ переименовать модель с помощью Django / South?

Я искал ответ на это на сайте Юга, Google, и так, но не мог найти простой способ сделать это.

Я хочу переименовать модель 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 to Bar, но игнорировать foo член FooTwo сейчас.

какой самый простой способ сделать это использование Юга?

  1. я, вероятно, мог бы сделать миграцию данных, но это кажется довольно сложным.
  2. напишите пользовательскую миграцию, например db.rename_table('city_citystate', 'geo_citystate'), но я не уверен, как исправить внешний ключ в этом случае.
  3. простой способ, который вы знаете?

4 ответов


чтобы ответить на ваш первый вопрос, простое переименование модели/таблицы довольно просто. Выполните команду:

./manage.py schemamigration yourapp rename_foo_to_bar --empty

(обновление 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 вариант в вашем классе модели. Но каждый раз, когда вы это делаете, вы увеличиваете унаследованный вес вашей кодовой базы-наличие имен классов отличается от имен таблиц делает ваш код сложнее понять и поддерживать. Я полностью поддерживаю выполнение простых рефакторингов, подобных этому, ради ясности.

(обновление) я просто попробовал это в производстве и получил странное предупреждение, когда я пошел применять миграцию. Он сказал:"!--9-->

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 вариант.


Я следил за решением Леопда выше. Но это не изменило названия моделей. Я изменил его вручную в коде (также в связанных моделях, где это называется FK). И сделал еще одну миграцию на юг, но с ... поддельным вариантом. Это делает имена моделей и таблиц одинаковыми.

только что понял, можно сначала начать с изменения имен моделей, а затем отредактировать файл миграции перед их применением. Более чистый.