Description
Deployment Type
Self-hosted
Triage priority
I volunteer to perform this work (if approved)
NetBox Version
v4.1.6
Python Version
3.11
Steps to Reproduce
It is possible to store a non-integer value in WeighMixin._abs_weight
fields (which are PositiveBigIntegerField
) prior to the object being persisted to the database. This potentially causes deserialization errors when populating a new object via a core serializer which uses the field's to_python
method.
Expected Behavior
The value of DeviceType._abs_weight
should be the same (an integer value) both before and after persistence and refresh from the DB.
Observed Behavior
In [9]: dt.weight = 10.234567
In [10]: dt.save()
In [11]: dt._abs_weight
Out[11]: 10.234567
In [12]: dt.refresh_from_db()
In [13]: dt._abs_weight
Out[13]: 10
As we see here, a DeviceType
object populated with a non-integer weight will have that non-integer value assigned to _abs_weight
until the object is persisted to the database and refreshed. If, however, the DeviceType
object is populated with data and not refreshed from the DB before it is used in another operation (such as deserialization into another DeviceType
object), a DeserializationError
is raised from the field's to_python
code which expects an integer but receives a float.
The cause is this code:
def save(self, *args, **kwargs):
# Store the given weight (if any) in grams for use in database ordering
if self.weight and self.weight_unit:
self._abs_weight = to_grams(self.weight, self.weight_unit)
else:
self._abs_weight = None
super().save(*args, **kwargs)
The output of to_grams
should be coerced to an int before being assigned to self._abs_weight
.
Note: Moved from netboxlabs/netbox-branching#162