GeneratedField with db_persist=False creates a database column anyway

I have the following model:

from django.db import models
from django.db.models import F, Func
from django.db.models.functions import Length
from django_reuse.abstract_models import Timestamped

class Painting(Timestamped):
    work_name = models.CharField(max_length=60)

    work_name_length = models.GeneratedField(
        # expression=Func(F('work_name'), function='Length'),
        expression=Length(F('work_name')),
        output_field=models.PositiveSmallIntegerField(),
        db_persist=False
    )

Everything seems to work okay, but when I open my Sqlite database, I see the generated field was persisted to the database anyway:

Not sure if I am doing something wrong, or if it is a bug, but if a column will be created in the database anyway, I would just use an IntegerField directly and do the calculation via overriding the save method.

I seem to get equivalent results, so is there any advantage to still using the newer field which seems to be broken, or perhaps just broken specfically with Sqlite?

from django.db import models
from django.db.models import F  # Func
from django.db.models.functions import Length
from django_reuse.abstract_models import Timestamped

class Painting(Timestamped):
    title = models.CharField(max_length=60)

    title_len = models.PositiveSmallIntegerField(blank=True)

    title_len_gen = models.GeneratedField(
        # expression=Func(F('title'), function='Length'),
        expression=Length(F('title')),
        output_field=models.PositiveSmallIntegerField(),
        db_persist=False
    )
    
    class Meta:
        ordering=['title']

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        self.title_len = len(self.title)
        super(Painting, self).save(*args, **kwargs)


How have you determined that a physical column has been created in the database? (Can you change that value and have it saved?)

Do you find this data in each row physically within that row?

You’re looking at the output of tool that shows all the columns in the table. From the perspective of the external API, that column does exist. An SQL DML statement isn’t going to detect whether the column is real or virtual.

Okay, so from this screenshot I guess I can safely assume this “column” is in fact virtual rather than stored?

I’m not sure whether that screenshot is definitive or not. That’s still working through the library’s API.

I think the only way to definitively answer your question would be to look at the structure of the db.sqlite3 file itself to see if the column exists physically in each row.

(Having said that, I’ve answered this question to my own satisfaction, but I don’t expect anyone else to accept my judgement on it.)

Well, opening the database file in Gedit, I see “Virtual” so I guess that’s enough for me, and based on docs elsewhere, it looks like Sqlite and MariaDB are the only options for me if I want a virtual column, I don’t see any plans from Postgres to support this in the near future.