﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
35969	Changing output_field for GeneratedField leads to ProgrammingError with Postgres 16.5+	Ryan Schave	Lufafa Joshua	"Consider the following model and assume the initial migration has been applied:

{{{#!python
class Order(models.Model):  
    order_no = models.IntegerField()  
    item_no = models.CharField(max_length=25)  
    qty = models.IntegerField()  
    cost = models.DecimalField(max_digits=10, decimal_places=2)  
    total_cost = models.GeneratedField(  
        expression=F(""cost"") * F(""qty""),  
        output_field=models.BigIntegerField(),  
        db_persist=True,  
    )
}}}

During a code review we determined the output field should be a Decimal field and the field was modified as follows:

{{{#!python
total_cost = models.GeneratedField(  
    expression=F(""cost"") * F(""qty""),  
    output_field=models.DecimalField(decimal_places=2, max_digits=16),  
    db_persist=True,  
)
}}}

And a new migration was generated:

{{{#!python
migrations.AlterField(  
    model_name='order',  
    name='total_cost',  
    field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('cost'), '*', models.F('qty')), output_field=models.DecimalField(decimal_places=2, max_digits=16)),  
),
}}}

In Postgres 16.4 and earlier, this migration is applied without error.  (I'm aware that the value of the total_cost field is not recomputed for existing records when this migration is applied.).

Starting with Postgres 16.5 and up, this migration fails with the following error:

{{{
psycopg2.errors.InvalidColumnDefinition: cannot specify USING when altering type of generated column
DETAIL:  Column ""total_cost"" is a generated column.
...
django.db.utils.ProgrammingError: cannot specify USING when altering type of generated column
}}}

This appears to be a result of the following change in Postgres 16.5 ([https://www.postgresql.org/docs/release/16.5/ release notes]): 

  Disallow a `USING` clause when altering the type of a generated column (Peter Eisentraut) [§](https://postgr.es/c/5867ee005)
  A generated column already has an expression specifying the column contents, so including `USING` doesn't make sense.

The Django [https://docs.djangoproject.com/en/5.1/ref/models/fields/#generatedfield documentation] for GeneratedField makes it clear that 

   There are many database-specific restrictions on generated fields that Django doesn’t validate and the database may raise an error

For this reason, I almost didn't open a ticket.  However, there is logic in db/backends/base/schema.py that checks if the expression of a GeneratedField changed.  Consider this migration (which changes the expression from multiplication to addition):

{{{#!python
migrations.AlterField(  
    model_name='order',  
    name='total_cost',  
    field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('cost'), '+', models.F('qty')), output_field=models.BigIntegerField()),  
),
}}}

Attempting to apply this migration will raise the following error (even in Postgres 16.4):

{{{
ValueError: Modifying GeneratedFields is not supported - the field sales.Order.total_cost must be removed and re-added with the new definition.
}}}

This error is more helpful.  It explains the problem better and even suggests a workaround.

Should we throw a similar error if the output_field of a GeneratedField is changed?  Or add a tip to the documentation?

The above was tested with:
Django version 5.1.3
psycopg2 version 2.9.10
Postgres versions: 16.4, 16.5, 16.6, 17.0, and 17.2"	Bug	closed	Migrations	5.1	Normal	fixed		Lily Foote Mariusz Felisiak Simon Charette	Ready for checkin	1	0	0	0	0	0
