Django - Как переименовать поле модели, используя South?

209

Я хотел бы изменить имя определенных полей в модели:

class Foo(models.Model):
    name = models.CharField()
    rel  = models.ForeignKey(Bar)

должен измениться на:

class Foo(models.Model):
    full_name     = models.CharField()
    odd_relation  = models.ForeignKey(Bar)

Какой самый простой способ сделать это, используя Юг?

Джонатан
источник
7
См. Также stackoverflow.com/questions/2862979/… для переименования модели, а не поля модели .
Механическая улитка

Ответы:

230

Вы можете использовать db.rename_columnфункцию.

class Migration:

    def forwards(self, orm):
        # Rename 'name' field to 'full_name'
        db.rename_column('app_foo', 'name', 'full_name')




    def backwards(self, orm):
        # Rename 'full_name' field to 'name'
        db.rename_column('app_foo', 'full_name', 'name')

Первым аргументом db.rename_columnявляется имя таблицы, поэтому важно помнить, как Django создает имена таблиц :

Django автоматически получает имя таблицы базы данных из имени класса вашей модели и приложения, которое его содержит. Имя таблицы базы данных модели создается путем присоединения «метки приложения» модели - имени, которое вы использовали в manage.py startapp - к имени класса модели с подчеркиванием между ними.

В том случае , если у вас есть мульти сформулированных, верблюжьего обсаженное имя образцового, такие как ProjectItem, имя таблицы будет app_projectitem(т.е. подчеркивание не будет вставлено между projectи itemдаже если они верблюжьими обсаженным).

googletorp
источник
2
Это будет работать на имя \ полное_имя, но не на поле отношения, верно?
Джонатан
23
ВАЖНОЕ ПРИМЕЧАНИЕ: если вы собираетесь использовать это, убедитесь, что «app_foo» - это имя таблицы базы данных, например: «mainapp_profile», «name» - это старое имя столбца базы данных (не имя поля модели), например: «user_id» и «full_name» будут новым именем, которое вы хотите иметь для столбца (опять же, столбец базы данных, а не имя поля). Итак: db.rename_column ('mainapp_profile', 'user_id', 'new_user_id') Кроме того, если вы имеете дело с внешними ключами, в них должна быть часть _id при переименовании.
Гезим
3
Если вы вручную сделаете это db.rename_column, вам, возможно, придется впоследствии выполнить поддельную схему миграции, чтобы очистить резервную копию. Это сначала перенести изменения с переименованием столбцов. Затем исправьте модель (чтобы иметь обновленное имя), а затем выполните приложение ./manage.py schemamigration --auto && ./manage.py Перенос приложения --fake).
Доктор Джимбоб
24
Вы также можете использовать ./manage.py schemamigration my_app renaming_column_x --empty, чтобы создать пустую миграцию и просто поместить в нее код
Илиан Илиев
11
--empty не очень помогает, вместо этого используйте --auto и измените созданную миграцию. Таким образом, он не будет утверждать, что поле было удалено для следующей миграции models.py.
1913 года
39

Вот что я делаю:

  1. Измените имя столбца в вашей модели (в этом примере это будет myapp/models.py)
  2. Бегать ./manage.py schemamigration myapp renaming_column_x --auto

Заметка renaming_column_xможет быть чем угодно, это просто способ дать описательное имя файлу миграции.

Это создаст вам файл с именем, myapp/migrations/000x_renaming_column_x.pyкоторый удалит ваш старый столбец и добавит новый столбец.

Измените код в этом файле, чтобы изменить поведение миграции на простое переименование:

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming column 'mymodel.old_column_name' to 'mymodel.new_column_name'
        db.rename_column(u'myapp_mymodel', 'old_column_name', 'new_column_name')

    def backwards(self, orm):
        # Renaming column 'mymodel.new_column_name' to 'mymodel.old_column_name'
        db.rename_column(u'myapp_mymodel', 'new_column_name', 'old_column_name')
donturner
источник
как называется столбец в вашей команде? xили column_x?
Andilabs
Часть команды, на которую вы ссылаетесь, просто используется для обозначения миграции, она может быть любой, какой вам нравится. Имя столбца нужно будет указать в файле миграции при его редактировании.
donturner
2
--autoПервым делом создайте миграцию. Это позволяет избежать проблем с South ORM Freezer, которые возникают, если миграция имеет только методы forwardsи backwardsметоды, но не содержит замороженный modelобъект.
MWZ
Как мне ответить на вопрос Юга «Поскольку вы удаляете это поле, вы ДОЛЖНЫ указать значение по умолчанию»?
Брайс
3
Одна проблема, с которой я столкнулся при использовании этого метода, заключается в том, db.rename_columnчто не переименовываются ограничения, связанные со столбцом. Миграция все еще будет работать, но у вас будут ограничения, названные в честь старого имени столбца. У меня был столбец с ограничением уникальности, я переименовал его с помощью этого метода, проверил, что ограничение уникальности все еще существует, и получил ошибку, но имя самого ограничения все еще использует старое имя столбца. Возможно, явный db.delete_uniqueи db.create_uniqueсделал бы это, но я решил пойти с решением sjh.
Луи
15

Я не знал о столбце db.rename, звучит удобно, однако в прошлом я добавлял новый столбец как одну схему миграции, затем создавал миграцию данных для перемещения значений в новое поле, а затем вторую схему миграции для удаления старого столбца

SJH
источник
Я тоже. Проблема с техникой schema-data-schema заключается в том, что в итоге вы получаете разные имена для ваших полей / моделей. Иногда это проблема, если вы используете канонические имена для включения диспетчеров ...
Джонатан
Я просто попробовал это, и это не сработало, так как произошел конфликт имен. У меня был точно такой же FK, но другое имя. Это не подтвердило. Так что не делай этого.
Гезим
2
@jonathan, он хочет разные имена! ... @pilgrim, хочешь написать какой-нибудь код? Я делал это несколько раз на этой неделе, если ваши модели не проверяются, то юг не будет создавать миграции.
SJH
Это будет работать, но, вероятно, будет медленнее, чем «rename_column», который предложили другие люди. Я знаю, что MySQL может сделать «ALTER TABLE ... переименовать столбец» (или что-то еще) довольно быстро.
Рори
1
@Rory db.rename_columnне будет переименовывать ограничения для вас, поэтому вам придется обрабатывать это вручную. Если вы забудете это сделать, миграция будет работать за исключением того, что без вашего ведома может быть ограничение, все еще использующее старое имя столбца. Мне неясно, является ли проблема просто косметической или в будущей миграции, где ограничение должно быть изменено или отменено, Юг не сможет его найти. В любом случае, делать это здесь, как предполагает sjh, - это безопасный способ сделать это: вы можете позволить Югу понять, что он должен выяснить.
Louis
10

Джанго 1.7 ввел миграцию так что теперь вам даже не нужно устанавливать дополнительный пакет для управления миграциями.

Чтобы переименовать вашу модель, вам нужно сначала создать пустую миграцию:

$ manage.py makemigrations <app_name> --empty

Затем вам нужно отредактировать код вашей миграции следующим образом:

from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
    ('yourapp', 'XXXX_your_previous_migration'),
]

operations = [
    migrations.RenameField(
        model_name='Foo',
        old_name='name',
        new_name='full_name'
    ),
    migrations.RenameField(
        model_name='Foo',
        old_name='rel',
        new_name='odd_relation'
    ),
]

И после этого вам нужно запустить:

$ manage.py migrate <app_name>
Дмитрий Михайлов
источник
5

Просто поменяйте модель и запустите makemigrationsв 1.9

Django автоматически определяет, что вы удалили и создали одно поле, и спрашивает:

Did you rename model.old to model.new (a IntegerField)? [y/N]

Скажи да, и правильная миграция будет создана. Магия.

Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
0
  1. Добавьте southк установленным приложениям в файле настроек проекта.
  2. Закомментируйте добавленное / измененное поле / таблицу.
  3. $ manage.py Schemamigration <app_name> --initial
  4. $ manage.py migrate <app_name> --Fake
  5. Откомментируйте поле и напишите измененное
  6. $ manage.py Schemamigration --auto
  7. $ manage.py migrate <app_name>

Если вы используете «pycharm», то вы можете использовать «ctrl + shift + r» вместо «manage.py» и «shift» для параметров.

анчо
источник