Skip to content

Unable to save through Django admin #112

@devenvyas

Description

@devenvyas

Hi,

When I try to save an admin form which has a MeasurementField, I get the following error:

    change_message = self.construct_change_message(
  File "/home/ubuntu/ENTER/envs/athena39/lib/python3.9/site-packages/django/contrib/admin/options.py", line 1179, in construct_change_message
    return construct_change_message(form, formsets, add)
  File "/home/ubuntu/ENTER/envs/athena39/lib/python3.9/site-packages/django/contrib/admin/utils.py", line 522, in construct_change_message
    changed_data = form.changed_data
  File "/home/ubuntu/ENTER/envs/athena39/lib/python3.9/site-packages/django/utils/functional.py", line 49, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/ubuntu/ENTER/envs/athena39/lib/python3.9/site-packages/django/forms/forms.py", line 484, in changed_data
    return [name for name, bf in self._bound_items() if bf._has_changed()]
  File "/home/ubuntu/ENTER/envs/athena39/lib/python3.9/site-packages/django/forms/forms.py", line 484, in <listcomp>
    return [name for name, bf in self._bound_items() if bf._has_changed()]
  File "/home/ubuntu/ENTER/envs/athena39/lib/python3.9/site-packages/django/forms/boundfield.py", line 154, in _has_changed
    return field.has_changed(initial_value, self.data)
  File "/home/ubuntu/ENTER/envs/athena39/lib/python3.9/site-packages/django/forms/fields.py", line 1164, in has_changed
    initial = self.widget.decompress(initial)
  File "/home/ubuntu/ENTER/envs/athena39/lib/python3.9/site-packages/django_measurement/forms.py", line 36, in decompress
    unit = value.STANDARD_UNIT
AttributeError: 'str' object has no attribute 'STANDARD_UNIT'

The decompress function in the widget at times will receive the value arg as str => 120.0 g and breaks because it expects the value to be an instance of measurement class. This is preventing me from saving changes through the Django admin panel.

The following (adding an instance check) seems to be working although I am not sure if this is the right way to handle the issue:

def decompress(self, value):
    if value:
        if isinstance(value, str):
            magnitude, unit = [v.strip() for v in value.split(' ')]
            return [float(magnitude), unit]
        elif isinstance(value, MeasureBase):
            choice_units = set([u for u, n in self.unit_choices])
            unit = value.STANDARD_UNIT
            if unit not in choice_units:
                unit = choice_units.pop()

            magnitude = getattr(value, unit)
            return [magnitude, unit]

    return [None, None]

You can recreate this issue with the following model:

from django.db import models
from django_measurement.models import MeasurementField
from measurement.measures import Weight

def zero_weight():
  return Weight(kg=0)

class Product(models.Model):
  net_weight = MeasurementField(measurement=Weight, default=zero_weight)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions