Как обновить удаленные варианты моделей в Django, не нарушая существующие значения базы данных?
Я работаю над проектом на Django, где мы используем models.TextChoices для таких полей, как current_status. Наш клиент запросил изменения формулировок — например, переименование "Contacted" в "Contacted for assessment", "Booked" в "Assessment booked" и так далее.
Предыдущее перечисление:
class ClientStatus(models.TextChoices):
CONTACTED = "Contacted"
BOOKED = "Booked"
Обновленное перечисление:
class ClientStatus(models.TextChoices):
CONTACTED_FOR_ASSESSMENT = "Contacted for assessment", "Contacted for assessment"
ASSESSMENT_BOOKED = "Assessment booked", "Assessment booked"
<время работы/>
Проблема
У нас в базе данных уже есть сотни пользователей с:
current_status = 'Contacted'
Поскольку "Contacted" больше не существует в выборе модели:
- Будут ли миграции завершаться неудачно или будут вести себя неожиданно?
- Будут ли нарушены представления администратора Django или API при обнаружении этих устаревших значений?
- Как правильно переименовать выбранные значения , не оставляя несогласованных данных?
Ограничения
Мы хотим избежать ненужных миграций. Мы хотим, чтобы это работало во всех средах (dev/staging/production). Мы бы предпочли не ломать панель администратора или сериализаторы.
<время работы/>Вопрос
Каков самый безопасный и понятный для Django способ переименовывать или удалять значения перечисления, когда старые данные уже существуют в базе данных?
Можно ли обновлять SQL вручную? Или есть рекомендуемый подход к миграции на Django?
Что я пробовал
Запускались python manage.py makemigrations и migrate. Перенос не завершился ошибкой.
При попытке редактирования пользователей со старыми значениями в режиме администратора возникают ошибки.
Я рассматривал возможность исправления SQL вручную:
UPDATE api_user
SET current_status = 'Contacted for assessment'
WHERE current_status = 'Contacted';
<время работы/>
вам следует просто отредактировать модели, а затем выполнить sql-код, чтобы убедиться, что нет возможности "связаться" с какой-либо записью в качестве current_status , вы на правильном пути.
Из вашего описания следует, что вам нужны только изменения в представлении / отображении. Если это так и с сохранением предыдущих значений ("Связался", "Забронировал") в базе данных все в порядке, просто продолжайте в том же духе и измените только отображаемое значение:
class ClientStatus(models.TextChoices):
CONTACTED = "Contacted", "Contacted for assessment"
BOOKED = "Booked", "Assessment booked"
Обратите внимание, что в приведенном выше коде первое значение в кортеже такое же, как и у вас было раньше, и единственное изменение - это явное добавление отображаемого значения. Формы Django и т.д. будет автоматически использоваться отображаемое значение, если вам нужно отобразить его в шаблонах вручную, используйте метод get_FOO_display (Обратите внимание, что foo следует заменить на имя поля)
Если вы действительно хотите изменить значения в базе данных, обновите перечисление, как вы это сделали, и обновите данные в базе данных. Рекомендуемый способ обновления данных - создать перенос данных. Запустите python manage.py makemigrations --empty yourappname (замените "yourappname"), а затем измените созданный перенос:
from django.db import migrations
def update_choices(apps, schema_editor):
# We can't import the Person model directly as it may be a newer
# version than this migration expects. We use the historical version.
YourModel = apps.get_model("yourappname", "YourModel")
YourModel.objects.filter(your_field_name="Contacted").update(your_field_name="Contacted for assessment")
YourModel.objects.filter(your_field_name="Booked").update(your_field_name="Assessment booked")
class Migration(migrations.Migration):
# Other stuff like dependencies
operations = [
migrations.RunPython(update_choices),
]