Как обновить удаленные варианты моделей в 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" больше не существует в выборе модели:

  1. Будут ли миграции завершаться неудачно или будут вести себя неожиданно?
  2. Будут ли нарушены представления администратора Django или API при обнаружении этих устаревших значений?
  3. Как правильно переименовать выбранные значения , не оставляя несогласованных данных?
<время работы/>

Ограничения

Мы хотим избежать ненужных миграций. Мы хотим, чтобы это работало во всех средах (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),
    ]
Вернуться на верх