Перемещение модели из одного приложения в другое в django

В django достаточно сложно делать рефакторинг, а именно перемещать модели из одного приложения в другое, но всё же попробуем решить эту проблему исходя из ответа в stackoverflow

Допустим есть модель Widget и мы переносим её из старого приложения main в новое приложение widget

Самым первым шагом - копируем текст модели из main/models.py в widget/models.py, и только потом продолжаем. Выполняем команду.

python manage.py makemigrations main --empty

Этой командой мы делаем миграцию для старого приложения. Заполняем её примерно следующим контентом

class Migration(migrations.Migration):
    dependencies = [
        ('main', '0021_auto_20210525_1659'),
    ]

    database_operations = [
        migrations.AlterModelTable('Widget', 'widget_widget')
    ]

    state_operations = [
        migrations.DeleteModel('Widget')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]
SeparateDatabaseAndState нужен для того, чтобы разделить операции, которые выполняются над классами django и в базе данных. По сути мы переименовываем таблицу для модели Widget, т.к. эта модель у нас была в приложении model. Далее мы знакомим django с тем, что модель удаляется из приложения main.

Теперь будем работать с новым приложением widget. 

python manage.py makemigrations widget

Эта команда сгенерирует для Вас миграцию по созданию модели Widget. Но тут есть опять же нюанс. Мы не должны реально создавать таблицу для модели. Мы должны использовать существующую таблицу. Поэтому мы также как и в первом случае должны разделить нашу миграцию на state и databes операции. Однако оставим из миграции кое-что (например fields).


class Migration(migrations.Migration):
    initial = True

    dependencies = [
        ('sites', '0002_alter_domain_unique'),
    ]

    state_operations = [
        migrations.CreateModel(
            name='Widget',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('updated_at', models.DateTimeField(auto_now=True)),
            ],
            options={
                'db_table': 'widget_widget',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

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

SeparateDatabaseAndState - также разделит операции на выполняемые в базе и для django. Готово. Теперь можно запустить команду migrate и всё встанет на свои места. Будьте осторожны и не выполняйте миграцию, пока не будете в ней уверен на production. А лучше делайте бэкапы как можно чаще!