Opened 8 months ago

Closed 8 months ago

Last modified 8 months ago

#34877 closed Bug (fixed)

KeyError for output_field in GeneratedField

Reported by: Paolo Melchiorre Owned by: Paolo Melchiorre
Component: Database layer (models, ORM) Version: 5.0
Severity: Release blocker Keywords: field, database, generated, output_field
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Paolo Melchiorre)

Trying to get SQL code for a migration I receive a KeyError.

Model

Example of a model with a GenratedField.

from decimal import Decimal
from django.db import models
from django.db.models import F, Value as V
from django.db.models.functions import Round

class Item(models.Model):
    price = models.DecimalField(max_digits=7, decimal_places=2)
    vat_price = models.GeneratedField(
        db_persist=True,
        expression=Round(F("price") * V(Decimal("1.22")), 2),
        output_field=models.DecimalField(max_digits=8, decimal_places=2),
    )

Step

Generate the migration file:

$ python -m manage makemigrations

Steps to generate the error:

$ python -m manage sqlmigrate shop 0001

Similar error with another command:

$ python -m manage migrate shop 0001

Traceback

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/paulox/Projects/generatedfield/manage.py", line 22, in <module>
    main()
  File "/home/paulox/Projects/generatedfield/manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/core/management/__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/core/management/base.py", line 412, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/core/management/commands/sqlmigrate.py", line 38, in execute
    return super().execute(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/core/management/base.py", line 458, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/core/management/commands/sqlmigrate.py", line 80, in handle
    sql_statements = loader.collect_sql(plan)
                     ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/db/migrations/loader.py", line 381, in collect_sql
    state = migration.apply(state, schema_editor, collect_sql=True)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/db/migrations/migration.py", line 132, in apply
    operation.database_forwards(
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/db/migrations/operations/models.py", line 96, in database_forwards
    schema_editor.create_model(model)
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/db/backends/base/schema.py", line 506, in create_model
    self.deferred_sql.extend(self._model_indexes_sql(model))
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/db/backends/base/schema.py", line 1595, in _model_indexes_sql
    output.extend(self._field_indexes_sql(model, field))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/db/backends/postgresql/schema.py", line 63, in _field_indexes_sql
    like_index_statement = self._create_like_index_sql(model, field)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/db/backends/postgresql/schema.py", line 88, in _create_like_index_sql
    db_type = field.db_type(connection=self.connection)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/db/models/fields/__init__.py", line 879, in db_type
    return column_type % data
           ~~~~~~~~~~~~^~~~~~
  File "/home/paulox/Projects/generatedfield/.venv/lib/python3.11/site-packages/django/utils/datastructures.py", line 280, in __getitem__
    value = super().__getitem__(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: 'max_digits'

Expected result

BEGIN;
--
-- Create model Item
--
CREATE TABLE "shop_item" (
    "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    "price" numeric(7, 2) NOT NULL,
    "vat_price" numeric(8, 2) GENERATED ALWAYS AS (ROUND(("price" * 1.22), 2)) STORED
);
COMMIT;

Change History (7)

comment:1 by Paolo Melchiorre, 8 months ago

Description: modified (diff)

comment:2 by Simon Charette, 8 months ago

Triage Stage: UnreviewedAccepted

Seems like we missed a db_type_parameters override

  • django/db/models/fields/generated.py

    diff --git a/django/db/models/fields/generated.py b/django/db/models/fields/generated.py
    index deb5875638..5fbd4c4fdd 100644
    a b def get_internal_type(self):  
    161161
    162162    def db_parameters(self, connection):
    163163        return self.output_field.db_parameters(connection)
     164
     165    def db_type_parameters(self, connection):
     166        return self.output_field.db_type_parameters(connection)

comment:3 by Paolo Melchiorre, 8 months ago

Has patch: set
Owner: changed from nobody to Paolo Melchiorre
Status: newassigned

in reply to:  2 comment:4 by Paolo Melchiorre, 8 months ago

Replying to Simon Charette:

Seems like we missed a db_type_parameters override

Thanks again Simon.

I opened a PR based on your suggestion.

comment:5 by Mariusz Felisiak, 8 months ago

Triage Stage: AcceptedReady for checkin

comment:6 by Mariusz Felisiak <felisiak.mariusz@…>, 8 months ago

Resolution: fixed
Status: assignedclosed

In e7e8eb44:

Fixed #34877 -- Fixed migrations crash when adding GeneratedField with output_field with params.

comment:7 by Mariusz Felisiak <felisiak.mariusz@…>, 8 months ago

In 0f9d0739:

[5.0.x] Fixed #34877 -- Fixed migrations crash when adding GeneratedField with output_field with params.

Backport of e7e8eb44a30bcab004a582760752b5eb3fcd6e91 from main

Note: See TracTickets for help on using tickets.
Back to Top