Как уменьшить 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
),
]