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».

