django-computedfields
django-computedfields provides autoupdated database fields
for model methods.
Tested with Django 3.2 and 4.2 (Python 3.8 to 3.11).
Example
Just derive your model from ComputedFieldsModel
and place
the @computed
decorator at a method:
from django.db import models
from computedfields.models import ComputedFieldsModel, computed
class MyModel(ComputedFieldsModel):
name = models.CharField(max_length=32)
@computed(models.CharField(max_length=32), depends=[('self', ['name'])])
def computed_field(self):
return self.name.upper()
computed_field
will be turned into a real database field
and can be accessed and searched like any other database field.
During saving the associated method gets called and it’s result
written to the database.
How to recalculate without saving the model record
If you need to recalculate the computed field but without saving it, use
from computedfields.models import compute
>>> from computedfields.models import compute
>>> person = MyModel.objects.get(id=1)
>>> person.computed_field
>>> person.name = 'nina'
>>> compute(person, 'computed_field')
>>> person.computed_field
>>> person.save()
>>> person.computed_field
depends
keyword
The depends
keyword argument can be used with any relation to indicate dependencies to fields on other models as well:
from django.db import models
from computedfields.models import ComputedFieldsModel, computed
class MyModel(ComputedFieldsModel):
name = models.CharField(max_length=32)
fk = models.ForeignKey(SomeModel)
@computed(
models.CharField(max_length=32),
depends=[
('self', ['name']),
('fk', ['fieldname'])
]
)
def computed_field(self):
return self.name.upper() + self.fk.fieldname
Now changes to self.name
, fk
or fk.fieldname
will update computed_field
.
Alternative Syntax
Instead of using the @computed
decorator with inline field definitions,
you can also use a more declarative syntax with ComputedField
, example from above rewritten:
from django.db import models
from computedfields.models import ComputedFieldsModel, ComputedField
def get_upper_string(inst):
return inst.name.upper()
class MyModel(ComputedFieldsModel):
name = models.CharField(max_length=32)
computed_field = ComputedField(
models.CharField(max_length=32),
depends=[('self', ['name'])],
compute=get_upper_string
)
Documentation
The documentation can be found here.
Changelog