On Thursday 16 November 2017 14:08:20 Sjoerd Job Postmus wrote:
> I disagree with not being able to calculate it locally (without the
> database): such a calculation depends on other fields. What if a dependent
> field is updated, but the object is not yet saved. What should the value
> be?
>
> >>> c.age, c.is_adult
>
> 17, False
>
> >>> c.age = 40
> >>> c.age, c.is_adult
>
> 40, False
>
> Would not make sense to me.
>
While I agree with the gist of this argument, I don't believe in parallel
computations -- that is, having some database-definition of a computed column
emulated in Python. Such computations always end up slightly different in some
edge cases (different precision, different rounding rules, different timezones
between webserver and database server, etc) and this can lead to obscure
heizenbugs and weird, hard-to-track data corruptions.
I see three solutions:
1) Make all computations in Python. This means the feature can be supported
only on databases which can run Python as part of their queries; I'm not quite
sure about the details, but I think PG can. I'm certain none of the other core
databases can, perhaps MSSQL can with IronPython.
2) Just invalidate all calculated columns as soon a change in the model
occurs. So then,
>>> c.age, c.is_adult
17, False
>>> c.age = 40
>>> c.is_adult
StaleCalculatedFieldException
3) If we claim that the calculated field is, essentially, a declarative
shorthand for .annotate(), then treat it as such -- and live with the result
whcih Sjoerd Job described as nonsensical. However, to make it a little less
nonsensical, we'd call the field something like "DBCalculatedField", to point
out that it isn't updated automatically in the model instance.
BTW, with annotate we already have that "nonsensical" behavior today, and
people seem to accept it:
class Teacher(models.Model):
pass
class Student(models.Model):
teacher = models.ForeignKey(Teacher)
...
>>> t = Teacher.objects.annotate(std_count=Count('student')).get(pk=1)
>>> t.std_count
16
>>> Student.objects.create(teacher=t)
>>> t.std_count
16
I understand that the perception may be different for calculated fields which
depend purely on "in-record" fields -- but I don't see a good way to verify
that property on the caclulated field definition, so I suspect the best (or,
rather, least bad) solution is just to change that perception.
Shai