Search code examples
pythondjangopostgresqlschema-migration

What happens with the existing data if Decimals decimal_places are changed in a Django model?


I need to change a DecimalField from having decimal_places=0 to decimal_places=7 while keeping max_digits=50. I think all numbers in this column are between 0 and 1,000,000,000. So the data migration could be unproblematic. However, I'm uncertain.

I have seen the AlterField documentation and I think I found the source code. However, I would need an introduction to this. Is it possible to see the generated SQL queries?

I could imagine several things going wrong:

  • Data Dropping if Decimal(decimal_places=0) is different from Decimal(decimal_places=7) in a way that Django/Postgres does not take care of
  • Data Change if the internal representation stays the same but the values are interpreted in a different way
  • Overflow if values get out of bounds
  • NaN / NULL if values get out of bounds

The last two cases should not happen in my specific case, but I'm still interested how Django migrations would deal with out of bounds cases.


Solution

  • Is it possible to see the generated SQL queries?

    Yes it is possible to see the generated SQL Query. You can do that by using the sqlmigrate [Django docs] management command (app_label is the name of your app and migration_name is the name of the migration, e.g. 0001, 0002, etc.):

    python manage.py sqlmigrate <app_label> <migration_name>
    

    This outputs for me the following SQL:

    BEGIN;
    --
    -- Alter field field_name on model_name
    --
    ALTER TABLE "table_name" ALTER COLUMN "field_name" TYPE numeric(50, 7);
    COMMIT;
    

    As to your question if this can go wrong, according to the PostgeSQL docs on Numeric Types: 8.1.2. Arbitrary Precision Numbers:

    if the number of digits to the left of the decimal point exceeds the declared precision minus the declared scale, an error is raised.

    Also from the PostgreSQL documentation Modifying Tables: 5.5.6. Changing a Column's Data Type:

    This will succeed only if each existing entry in the column can be converted to the new type by an implicit cast. If a more complex conversion is needed, you can add a USING clause that specifies how to compute the new values from the old.

    Hence if your migration would not be possible it would cause an error.