﻿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
36792	Add support for virtual generated columns (PostgreSQL 18+) in GeneratedField	Paolo Melchiorre		"=== Background ===
PostgreSQL 18 introduces virtual generated columns: columns declared with
GENERATED ALWAYS AS ( <generation_expr> ) VIRTUAL are computed at query time
and do not occupy storage. PostgreSQL 18 also makes VIRTUAL the default for
generated columns while continuing to support STORED (materialized) generated
columns. See the PostgreSQL 18 release notes: [https://www.postgresql.org/about/news/postgresql-18-released-3142/ PostgreSQL 18 release notes].

=== Motivation ===
Django's GeneratedField support currently targets databases that support STORED
(materialized) generated columns. With PostgreSQL 18, users should be able to
declare GeneratedFields that are VIRTUAL (computed at query time) and have
Django generate the correct DDL and perform correct introspection and
migration autogeneration.

=== Goals ===
* Add support in Django's PostgreSQL backend to emit the VIRTUAL keyword in
  CREATE TABLE and ALTER TABLE statements for generated columns when targeting
  PostgreSQL 18 or newer.
* Extend PostgreSQL introspection to detect whether an existing generated
  column is STORED or VIRTUAL and populate migration state accordingly so
  autogeneration can produce correct AddField / AlterField operations.
* Ensure migration operations handle switching between STORED and VIRTUAL
  where supported by the server, and emit clear errors or warnings when not
  supported by the connected server version.
* Add tests and documentation; skip/guard tests on PostgreSQL servers older
  than 18.

=== Implementation notes and suggestions ===
* Server gating: use the existing {{{server_version_int}}} checks (treat PostgreSQL 18 as the cutoff, e.g. {{{180000}}}) so that DDL including VIRTUAL is only emitted on servers that support it.
* DDL generation: update the PostgreSQL schema editor (schema creation/alter) to emit either ""VIRTUAL"" or ""STORED"" based on field metadata and server version. If the field model exposes a {{{stored}}} boolean, emit {{{STORED}}} when True and {{{VIRTUAL}}} when False (and server >= 18).
* Introspection: extend postgresql introspection to read the generation expression and the storage type (stored vs virtual) from {{{information_schema}}} and/or {{{pg_catalog}}} and expose those details in the field_info consumed by the migration autogenerator.
* Migrations: ensure {{{AlterField}}} and {{{AddField}}} include the storage attribute and that migration autogeneration treats changes in stored/virtual as schema changes. If the connected server does not support VIRTUAL, raise a clear error during migration planning/execution.
* Tests: add backend tests that:
  * create a model with a GeneratedField stored=True (STORED) and stored=False (VIRTUAL),
  * introspect an existing table with VIRTUAL columns,
  * autogenerate migrations for switching between STORED and VIRTUAL,
  * ensure tests are skipped on PostgreSQL < 18.
* Documentation: update GeneratedField docs to describe the stored vs virtual option and PostgreSQL version requirements (PG 18+ for VIRTUAL). Recommend keeping DB versions consistent across environments.

=== Examples ===
SQL (PG18+):
{{{
CREATE TABLE example (
    a integer,
    b integer GENERATED ALWAYS AS (a + 1) VIRTUAL
);
}}}

Stored column:
{{{
CREATE TABLE example (
    a integer,
    b integer GENERATED ALWAYS AS (a + 1) STORED
);
}}}

Django (draft API):
{{{
class MyModel(models.Model):
    width = models.IntegerField()
    area = models.GeneratedField(models.F('width') * 2, stored=False)  # VIRTUAL on PG18+
}}}

=== Backward-compatibility and migration considerations ===
* Emit {{{VIRTUAL}}} only when connected to PG 18+; otherwise use {{{STORED}}} or raise a clear error.
* Autogenerated migrations created on PG18 that include {{{VIRTUAL}}} should be documented or guarded to avoid failures on older servers.
* Recommend teams keep DB versions consistent across dev/test/prod if they plan to use {{{VIRTUAL}}} columns.

=== Related ===
* Similar work for Oracle persisted generated fields: [https://code.djangoproject.com/ticket/36765 #36765]
* PostgreSQL 18 release notes: [https://www.postgresql.org/about/news/postgresql-18-released-3142/]"	New feature	closed	Database layer (models, ORM)	dev	Normal	duplicate	postgresql		Unreviewed	0	0	0	0	0	0
