Django tries to write to a generated column
Asked Answered
D

2

8

I've added GIN index to my db

ALTER TABLE mtn_order
ADD COLUMN textsearchable_index_col tsvector
GENERATED ALWAYS AS (to_tsvector('english', coalesce(descr, '') || ' ' || coalesce(descrrep, ''))) STORED;
CREATE INDEX textsearch_idx ON mtn_order USING GIN (textsearchable_index_col);

and textsearchable_index_col = SearchVectorField(null=True) to my model and now when i'm trying to save new instance i get:

ProgrammingError at /order/create/
cannot insert into column "textsearchable_index_col"
DETAIL:  Column "textsearchable_index_col" is a generated column.

How to stop Django trying to write None to that field

Dorrisdorry answered 15/5, 2020 at 1:25 Comment(0)
L
5

You won't be able to add it as a field to your model, because Django will try to write values back to it.

You could annotate it on when you need to:

MyModel.objects.annotate(
    index_col=RawSQL('textsearchable_index_col', 
                     [], 
                     output_field=SearchVectorField()
)
Lemon answered 17/6, 2020 at 1:50 Comment(4)
For those of you wishing to track generated columns without having to resort to rawsql calls, follow this django project ticket: code.djangoproject.com/ticket/30511Peonir
That ticket looks like it’s limited to generated as identity columns?Lemon
I'd also thought that, but the django community closes tickets and marks them as duplicates for any GENERATED AS functionality and points back to the ticket I previously linked. Examples: code.djangoproject.com/ticket/31565 and code.djangoproject.com/ticket/31300Peonir
I think the suggestion is that the infrastructure and functionality for any GENERATED AS columns would be resolved by #30511.Lemon
H
0

Override the _do_insert and _do_update methods on the model:

class MTNOrder:

    def _do_insert(self, manager, using, fields, update_pk, raw):
        fields = [
            f for f in fields if f.attname not in ['textsearchable_index_col']
        ]
        return super()._do_insert(manager, using, fields, update_pk, raw)

    def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_update):
        values = [
            value for value in values if value[0].attname not in ['textsearchable_index_col']
        ]
        return super()._do_update(base_qs, using, pk_val, values, update_fields, forced_update)

Reference: make django not insert certain fields

Heilungkiang answered 18/4, 2022 at 20:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.