Aidas Bendoraitis, автор книги «Django 3 Web Development Cookbook», рассказал, как переименовать приложение в Django.
Когда я начал работу над MVP (минимально жизнеспособным продуктом) моего проекта 1st things 1st, я сперва думал, что этот Django-проект будет посвящен приоритизации. Несколько лет спустя я понял, что этот проект по сути SaaS (software as a service, ПО как услуга), а приоритизация — лишь часть необходимого функционала для SaaS. В конечном итоге мне понадобилось переименовать приложение, чтобы получить более чистый и лучше организованный код. Вот как я это сделал.
0. Обновите ваш код и кодовую базу
Убедитесь, что вы сделали git pull последних изменений и выполнили все миграции базы данных.
[python_ad_block]1. Установите django-rename-app
Поместите django-rename-app
в pip requirements и установите его. Либо просто запустите следующую команду:
(venv)$ pip install django-rename-app
Внесите это приложение в INSTALLED_APPS в ваших настройках:
INSTALLED_APPS = [ # … "django_rename_app", ]
2. Переименуйте директории приложения
Смените старое имя (oldapp
) на новое (newapp
) в ваших приложениях и шаблонах.
3. Измените имя приложения там, где оно встречается в коде
Измените имя во всех ваших импортах, миграциях и путях шаблонов.
Можно сделать глобальный поиск oldapp
, а затем перебрать все результаты.
4. Запустите управляющую команду rename_app
Выполните следующую команду:
(env)$ python manage.py rename_app oldapp newapp
Эта команда заменит префикс имени в таблицах приложения и записях в таблицах django_content_type
и django_migrations
.
Если планируете обновить сервера стейджинга и продакшена, добавьте команду rename_app
перед запуском миграций в своих скриптах деплоймента (Ansible, Docker и т.п..).
5. Обновите индексы и ограничения
Наконец, создайте пустую миграцию базы данных для приложения с пользовательским кодом, чтобы обновить индексы и ограничения внешних ключей.
(env)$ python manage.py makemigrations newapp --empty --name rename_indexes
Заполните миграцию следующим кодом:
# newapp/migrations/0002_rename_indexes.py from django.db import migrations def named_tuple_fetch_all(cursor): "Return all rows from a cursor as a namedtuple" from collections import namedtuple desc = cursor.description Result = namedtuple("Result", [col[0] for col in desc]) return [Result(*row) for row in cursor.fetchall()] def rename_indexes(apps, schema_editor): from django.db import connection with connection.cursor() as cursor: cursor.execute( """SELECT indexname FROM pg_indexes WHERE tablename LIKE 'newapp%'""" ) for result in named_tuple_fetch_all(cursor): old_index_name = result.indexname new_index_name = old_index_name.replace( "oldapp_", "newapp_", 1 ) cursor.execute( f"""ALTER INDEX IF EXISTS {old_index_name} RENAME TO {new_index_name}""" ) def rename_foreignkeys(apps, schema_editor): from django.db import connection with connection.cursor() as cursor: cursor.execute( """SELECT table_name, constraint_name FROM information_schema.key_column_usage WHERE constraint_catalog=CURRENT_CATALOG AND table_name LIKE 'newapp%' AND position_in_unique_constraint notnull""" ) for result in named_tuple_fetch_all(cursor): table_name = result.table_name old_foreignkey_name = result.constraint_name new_foreignkey_name = old_foreignkey_name.replace( "oldapp_", "newapp_", 1 ) cursor.execute( f"""ALTER TABLE {table_name} RENAME CONSTRAINT {old_foreignkey_name} TO {new_foreignkey_name}""" ) class Migration(migrations.Migration): dependencies = [ ("newapp", "0001_initial"), ] operations = [ migrations.RunPython(rename_indexes, migrations.RunPython.noop), migrations.RunPython(rename_foreignkeys, migrations.RunPython.noop), ]
Запустите миграции:
(env)$ python manage.py migrate
Если что-то не работает так, как ожидалось, мигрируйте обратно, исправьте код и затем снова мигрируйте. Отменить миграцию можно путем миграции на один шаг до последней миграции. Например:
(env)$ python manage.py migrate 0001
6. Уборка
После применения миграции во всех необходимых окружениях можно подчистить их путем удаления django-rename-app из pip requirements и скриптов деплоймента.
Итоги
Редко удается построить систему, которая изначально будет отвечать всем вашим нуждам. Системы всегда требуют постоянного улучшения и рефакторинга. Используя миграции Django и django-rename-app, можно работать над сайтами в стиле Agile, чисто и гибко.
Перевод статьи «How to Rename a Django App».