Как уменьшить max_length CharField в Django, когда данные уже существуют в БД

У меня есть CharField на модели Django (1.9):

alias = models.CharField(max_length=50)

Приложение используется и уже имеет данные, и уже есть объекты, использующие все 50 символов. Какой самый простой способ уменьшить max_length этого поля без получения жалоб из производственной базы данных при попытке перехода? БД является postgresql, если это имеет значение.

3 ответа

Я думаю, что правильный путь - это просто перейти на терминал разработки Python и получить доступ ко всем объектам этой конкретной модели и обрезать значения для псевдонима следующим образом:

 for object in MyModel.objects.all():
      object.alias = object.alias[:REDUCED_LENGTH]
      object.save()

и, изменение max_length в CharField в вашей модели и запустить миграцию.

уменьшить max_length=50 до другого max_length=20

> python manage.py makemigrations
> python manage.py migrate

все новые данные, которые вы сохраните, будут работать с новой max_length

для существующих данных вы можете сделать простой скрипт

from myproject.models import Mymodel

for obj in Mymodel.objects.all():
    obj.Firstname = obj.Firstname[0:3]    
    obj.save()

Усечение данных, нарушающих новыеmax_lengthусловие может быть выполнено как часть миграции. В файле миграции, созданном Django, можно было бы добавить вызовRunPython, предоставляя функцию, которая находит оскорбительные экземпляры и исправляет их перед применением изменения к столбцу.

      from django.db import migrations, models


def forwards_func(apps, schema_editor):
    """Apply a forwards migration."""

    # Grab cached versions of models
    TheModel = apps.get_model('the_package', 'TheModel')
    db_alias = schema_editor.connection.alias

    # Find all models with affected data
    #    Note this is overly simplistic for the example. To be more
    #    targeted, consider a Q() filter, to find instances whose 
    #    field length is greater than the new maximum.
    instances = TheModel.objects.using(db_alias).exclude(
        the_field_being_shortened='',
    )

    # Truncate the data
    for instance in instances:
        # Note the simplicity for example, again. One may consider
        # preserving a shortened value, instead.
        instance.the_field_being_shortened = ''
        instance.save()


def reverse_func(apps, schema_editor):
    """Undo a migration."""

    # We cannot restore the data. Nothing to do here.
    pass


class Migration(migrations.Migration):

    dependencies = [
        ('the_package', 'the_last_migration'),
    ]

    operations = [
        # RunPython executes our functions
        migrations.RunPython(forwards_func, reverse_func),
        migrations.AlterField(
            # The field alterations as generated by Django
        ),
    ]
Другие вопросы по тегам