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 автоматично отримує ім’я таблиці бази даних від імені вашого модельного класу та програми, яка його містить. Ім'я таблиці бази даних моделі будується шляхом приєднання "ярлика додатка" моделі - імені, яке ви використовували в start.pp управління.py - до імені класу моделі, з підкресленням між ними.

У випадку, коли у вас є багатословна назва верблюда з назвою моделі, наприклад ProjectItem, назва таблиці буде app_projectitem(тобто, підкреслення не буде вставлено між, projectі itemнавіть якщо вони є у верблюді).


2
Це буде працювати над ім'ям \ full_name, але не над полем відношення, правда?
Джонатан

23
ВАЖЛИВО ПРИМІТКА: якщо ви будете використовувати це, переконайтеся, що "app_foo" - це ім'я таблиці бази даних, наприклад: "mainapp_profile", "ім'я" - це стара назва стовпця бази даних (не назва моделі моделі), наприклад: "user_id" та "full_name" - це нове ім'я, яке ви хочете мати у стовпці (знову ж, стовпець бази даних, а не назва поля). Отже: db.rename_column ('mainapp_profile', 'user_id', 'new_user_id') Також, якщо ви маєте справу з іноземними ключами, ви повинні мати в них частину "_id" під час перейменування.
Гезим

3
Якщо ви вручну це зробите db.rename_column, можливо, після цього вам доведеться зробити підроблену схему, щоб очистити речі. Це спочатку міграція змін шляхом перейменування стовпців. Потім виправте модель (мати оновлену назву), а потім зробіть ./manage.py додаток схемиграції --auto && ./manage.py перемістити додаток --файк).
д-р Джимбоб

24
Ви також можете використовувати ./manage.py schemamigration my_app перейменування_column_x - порожній, щоб створити порожню міграцію та просто розмістити в ній код
Ilian Iliev

11
--empty не дуже допомагає, натомість використовуйте --auto та модифікуйте створену міграцію. Таким чином, поле для претензій не буде видалено для наступної міграції models.py.
Яск

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')

як називається стовпець у вашій команді? xабо column_x?
andilabs

Частина команди, на яку ви посилаєтесь, просто використовується для іменування міграції, вона може бути будь-якою, що вам подобається. Ім'я стовпця потрібно буде вказати у файлі міграції під час редагування.
donturner

2
Створення --autoміграції спочатку - чудова порада. Це дозволяє уникнути проблем із морозильником South ORM, які виникають, якщо міграція має лише методи forwardsта backwardsметоди, але не містить замороженого modelоб'єкта.
mwcz

Як я можу відповісти на запитання півдня "Оскільки ви видаляєте це поле, ОБОВ'ЯЗКОВО вказувати за замовчуванням"?
Брайс

3
Одна з проблем у мене з цим методом полягає в тому, db.rename_columnщо не перейменовуйте обмеження, пов'язані зі стовпцем. Міграція все ще працюватиме, але у вас будуть обмеження, названі назви старої назви стовпців. У мене був стовпець з обмеженням унікальності, перейменували його за допомогою цього методу, перевірили, що обмеження унікальності все ще існує, і сталася помилка, але сама назва обмеження все ще використовувала стару назву стовпця. Можливо, явне db.delete_uniqueі db.create_uniqueзробило б це, але я вирішив піти з рішенням sjh.
Луї

15

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


Я також. Проблема з технікою schema-data-schema полягає в тому, що у вас є різні назви для ваших полів / моделей. Іноді це проблема, якщо ви використовуєте канонічні імена для включення диспетчерів ...
Джонатан

Я просто спробував це, і це не вийшло, оскільки виник конфлікт імен. У мене був такий самий ФК, але інша назва. Він не підтвердив. Отже, не робіть цього.
Гезим

2
@jonathan, він хоче різних імен! ... @pilgrim, хочете опублікувати якийсь код? Я робив це кілька разів на цьому тижні, якщо ваші моделі не підтверджують, то на південь не буде створено міграцій.
sjh

Це спрацювало б, але, ймовірно, буде повільніше, ніж "перейменувати колонку", яку запропонували інші люди. Я знаю, що MySQL може "СТАРОЛЬНУ ТАБЛИЦЮ ... перейменувати стовпець" (або як би там не було) досить швидко.
Рорі

1
@Rory db.rename_columnне буде перейменовувати обмеження для вас, тому вам доведеться це вручну обробляти. Якщо ви забудете це зробити, міграція буде працювати, за винятком того невідомого для вас, можливо, ще існує обмеження, що використовує стару назву стовпця. Мені незрозуміло, чи це питання є просто косметичним, чи в майбутній міграції, де обмеження слід маніпулювати або скинути Південь, не вдасться його знайти. У будь-якому випадку, зробити це тут, як пропонує sjh, це безпечний спосіб зробити це: ви можете дозволити Південному зрозуміти, що саме слід з'ясувати.
Луї

10

Django 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' замість 'management.py' та 'shift' для параметрів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.