Django: changing contents on a field on every save-like action
Before committing a record to the database, I want to do a sanity check on a certain field. More precisely, it is an ArrayField and I want to remove any NaN/None values and replace them by zero.
However, there are many ways to create said record. A user might MyObject().save(), or MyObject.objects.create(), or MyObject.objects.bulk_create(), and even MyObject.objects.bulk_update(field=my_field). I believe there are also ways in that Django Rest Framework might use.
How can I be sure that NaN/None is always replaced by zero before committing to the database? Should I overwrite all the above methods? Should I create a custom field that inherits from ArrayField but does all the data munging? What is the best practice?
I ended up taking my own advice and subclassed DecimalField into something that can turn NaNs into None:
NOTE python<3.10 type-hinting syntax
import math
from typing import Any, Union
from django.db.models.fields import DecimalField
class NanToNoneDecimalField(DecimalField):
"""Converts a NaN value to None because NaN is no longer
supported for DecimalField in in Django 4.2
"""
def to_python(self, value: Union[Any, None]) -> Union[Any, None]:
try:
if math.isnan(value):
return None
except TypeError:
pass
return super().to_python(value)