Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reduce max_length of CharField in Django when data already exists in db

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.

like image 962
43Tesseracts Avatar asked Oct 28 '25 04:10

43Tesseracts


2 Answers

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.

like image 76
Sijan Bhandari Avatar answered Oct 29 '25 19:10

Sijan Bhandari


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
        ),
    ]
like image 40
Hub Avatar answered Oct 29 '25 17:10

Hub



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!