4

I have a CharField on a Django (1.9) model:

alias = models.CharField(max_length=50)

The app is being used and already has data, and there are objects using all 50 characters already. What is the simplest method to reduce the max_length of this field without getting complaints from my production database when I try to migrate? DB is postgresql if it makes a difference.

43Tesseracts
  • 4,617
  • 8
  • 48
  • 94
  • do you want to keep those texts? or delete them? – Exprator May 18 '17 at 05:23
  • just change the definition in models.py ... this will enforce it from pythons side when setting new values but will not change the constraint on the db ... – Joran Beasley May 18 '17 at 05:41
  • `fron django.db.models import F;MyModels.objects.update(alias=F('alias')[:new_length])` (i think!) will shorten all existing fields if thats what your question is – Joran Beasley May 18 '17 at 05:46
  • @Exprator ideally just truncate the ones that are too long, but deleting them is fine too. – 43Tesseracts May 18 '17 at 06:32

3 Answers3

6

I think the right way would be simply go the development python terminal and access all the objects of that particular model and truncate the values for alias as:

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

and, the change the max_length in the CharField in your model and run migrations.

Sijan Bhandari
  • 2,941
  • 3
  • 23
  • 36
2

to reduce max_length=50 to other max_length=20

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

all new data that you save will work with new max_length

for exists data you can make simple script

from myproject.models import Mymodel

for obj in Mymodel.objects.all():
    obj.Firstname = obj.Firstname[0:3]    
    obj.save()
kojibhy
  • 51
  • 1
  • 5
1

Truncating data that violates the new max_length condition can be done as part of the migration. In the Django-generated migration file, one would add a call to RunPython, supplying a function that finds offending instances and corrects them, prior to applying the alteration to the column.

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
        ),
    ]
Hub
  • 41
  • 5