Customisation¶
Ways to customise the behavior of django-dirtyfields
Checking many-to-many fields.¶
WARNING: this m2m mode will generate extra queries to get m2m relation values each time you will save your objects. It can have serious performance issues depending on your project.
By default, dirty functions are not checking many-to-many fields.
They are also a bit special, as a call to .add()
method is directly
saving the related object to the database, thus the instance is never dirty.
If you want to check these relations, you should set ENABLE_M2M_CHECK
to True
in your model inheriting from
DirtyFieldsMixin
, use check_m2m
parameter and provide the values you want to test against:
class Many2ManyModel(DirtyFieldsMixin, models.Model):
ENABLE_M2M_CHECK = True
m2m_field = models.ManyToManyField(AnotherModel)
>>> model = Many2ManyModel.objects.create()
>>> related_model = AnotherModel.objects.create()
>>> model.is_dirty()
False
>>> model.m2m_field.add(related_model)
>>> model.is_dirty()
False
>>> model.get_dirty_fields(check_m2m={"m2m_field": {related_model.id}})
{}
>>> model.get_dirty_fields(check_m2m={"m2m_field": set()})
{'m2m_field': set([related_model.id])}
This can be useful when validating forms with m2m relations, where you receive some ids and want to know if your object in the database needs to be updated with these form values.
Checking a limited set of model fields.¶
If you want to check a limited set of model fields, you should set FIELDS_TO_CHECK
in your model inheriting from DirtyFieldsMixin
:
class ModelWithSpecifiedFields(DirtyFieldsMixin, models.Model):
boolean1 = models.BooleanField(default=True)
boolean2 = models.BooleanField(default=True)
FIELDS_TO_CHECK = ["boolean1"]
>>> model = ModelWithSpecifiedFields.objects.create()
>>> model.boolean1 = False
>>> model.boolean2 = False
>>> model.get_dirty_fields()
{'boolean1': True}
This can be used in order to increase performance.
Custom comparison function¶
By default, dirtyfields
compare the value between the database and the memory on a naive way (==
).
After some issues (with timezones for example), a customisable comparison logic has been added.
You can now define how you want to compare 2 values by passing a function on DirtyFieldsMixin:
from django.db import models
from dirtyfields import DirtyFieldsMixin
def your_function((new_value, old_value, param1):
# Your custom comparison code here
return new_value == old_value
class YourModel(DirtyFieldsMixin, models.Model):
compare_function = (your_function, {"param1": 5})
Have a look at dirtyfields.compare
module to get some examples.
Custom value normalisation function¶
By default, dirtyfields
reports on the dirty fields as is. If a date field was changed
the result of get_dirty_fields()
will return the current and saved datetime object.
In some cases it is useful to normalise those values, e.g., when wanting ot save the diff data as a json dataset in a database.
The default behaviour of using values as is can be changed by providing a normalise_function
in your model. That function can evaluate the value’s type and rewrite it accordingly.
This example shows the usage of the normalise function, with an extra paramter of a user’s timezone being passed as well:
import pytz
import datetime
from django.db import models
from dirtyfields import DirtyFieldsMixin
def your_normalise_function(value, timezone=None):
if isinstance(value, (datetime.datetime, datetime.date)):
if timezone:
return pytz.timezone(timezone).localize(value).isoformat()
else:
return value.isoformat()
else:
return value
def get_user_timezone():
return "Europe/London"
class YourModel(DirtyFieldsMixin, models.Model):
normalise_function = (your_normalise_function,
{"timezone": get_user_timezone()})