[![build](https://github.com/netzkolchose/django-computedfields/actions/workflows/build.yml/badge.svg)](https://github.com/netzkolchose/django-computedfields/actions/workflows/build.yml)
[![Coverage Status](https://coveralls.io/repos/github/netzkolchose/django-computedfields/badge.svg?branch=master)](https://coveralls.io/github/netzkolchose/django-computedfields?branch=master)


### django-computedfields ###

django-computedfields provides autoupdated database fields
for model methods.

Tested with Django 2.2 and 3.2 (Python 3.6 to 3.9).


#### Example ####

Just derive your model from `ComputedFieldsModel` and place
the `@computed` decorator at a method:

```python
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`

```python
>>> from computedfields.models import compute
>>> person = MyModel.objects.get(id=1)  # this is to retrieve existing record
>>> person.computed_field               # outputs 'BERTY'
>>> person.name = 'nina'                # changing the dependent field `name` to nina
>>> compute(person, 'computed_field')   # outputs 'NINA'
>>> person.computed_field               # outputs 'BERTY' because the `person` is not yet saved
>>> person.save()                       # the save will now alter the database record for `name` and `computed_field`
>>> person.computed_field               # outputs 'NINA'
```

#### `depends` keyword

The  `depends` keyword argument can be used with any relation to indicate dependencies to fields on other models as well:

```python
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` or `fk.fieldname` will update `computed_field`.


#### Documentation ####

The documentation can be found [here](https://django-computedfields.readthedocs.io/en/latest/index.html).


#### Changelog ####

- 0.1.5
    - fix error on model instance cloning
- 0.1.4
    - Django 3.2 support
- 0.1.3
    - better multi table inheritance support and test cases
    - explicit docs for multi table inheritance
- 0.1.2
    - bugfix: o2o reverse name access
    - add docs about model inheritance support
- 0.1.1
    - bugfix: add missing migration
- 0.1.0
    - fix recursion on empty queryset
    - dependency expansion on M2M fields
    - `m2m_changed` handler with filtering on m2m fields
    - remove custom metaclass, introducing *Resolver* class
    - new decorator `@precomputed` for custom save methods
    - old *depends* syntax removed
    - docs update
- 0.0.23:
    - Bugfix: Fixing leaking computed fields in model inheritance.
- 0.0.22:
    - Automatic dependency expansion on reverse relations.
    - Example documentation.
- 0.0.21:
    - Bugfix: Fixing undefined _batchsize for pickled map usage.
- 0.0.20
    - Use `bulk_update` for computed field updates.
    - Allow custom update optimizations with *select_related* and *prefetch_related*.
    - Respect computed field MRO in `compute`.
    - Allow updates on local computed fields from `update_dependent` simplifying bulk actions on `ComputedFieldsModel`.
- 0.0.19
    - Better graph expansion on relation paths with support for *update_fields*.
- 0.0.18
    - New *depends* syntax deprecating the old one.
    - MRO of local computed field methods implemented.
- 0.0.17
    - Dropped Python 2.7 and Django 1.11 support.
