Code Monkey home page Code Monkey logo

django-measurement's Introduction

version ci coverage license

Django Measurement

Easily use, manipulate, and store unit-aware measurement objects using Python and Django.

django.contrib.gis.measure has these wonderful 'Distance' objects that can be used not only for storing a unit-aware distance measurement, but also for converting between different units and adding/subtracting these objects from one another.

This module provides for a django model field and admin interface for storing any measurements provided by python-measurement.

Example use with a model:

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

class BeerConsumptionLogEntry(models.Model):
    name = models.CharField(max_length=255)
    volume = MeasurementField(measurement=Volume)

    def __str__(self):
        return f"{self.name} of {self.volume}"

entry = BeerConsumptionLogEntry()
entry.name = "Bear Republic Racer 5"
entry.volume = Volume(us_pint=1)
entry.save()

These stored measurement objects can be used in all of the usual ways supported by python-measurement too:

>>> from measurement.measures import Mass
>>> weight_1 = Mass(lb=125)
>>> weight_2 = Mass(kg=40)
>>> added_together = weight_1 + weight_2
>>> added_together
Mass(lb=213.18497680735112)
>>> added_together.kg  # Maybe I actually need this value in kg?
96.699
  • Documentation for django-measurement is available via Read the Docs.
  • Please post issues on GitHub.

django-measurement's People

Contributors

ashlett avatar bitdeli-chef avatar buddylindsey avatar coddingtonbear avatar codingjoe avatar cullan avatar iansprice avatar jtprince avatar pacu2 avatar pyup-bot avatar scopalaffairs avatar syphar avatar thijstriemstra avatar webit-mdowney avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-measurement's Issues

Calculation based on external model value

Hi,

Is it possible to have the measurement conversion look at a different field for the conversion?

What I'm looking for a way to convert different types of fuel between metric, imperial, but also between volume and weight. :)

Essentially, things like gallons per hour, litres per hour, grams per second, grams per hour.

For 1 type of fuel this is simple, just create a custom Fuel measure class and define the conversions there, then create a bi-dimensional measurement that has Fuel over time.

Now, the problem is that I have 2 main types of fuel: one at 0.721 kg/l, and one at 0.804 kg/l.

For multiple types of fuel, it needs to find the conversion somewhere else in the model class..

From the point of view of the field, it'll be in the parent (model) and there in a field with the value stored there.

Support for PostgreSQL ArrayField

When storing large time series fields we are required to model our data with

ArrayField(MeasurementField(measurement=Temperature)), size=1000)

This requires storing data with a unit for each value in the time series. When querying the database we have to loop through each individual measurement to reconstruct the array. It would be very helpful to have the ability to have an array data model similar to this:

MeasurementArrayField(measurement=Temperature), size=1000)

This would allow us to store a single unit value per array and retrieve the data as an array in a single operation.

KeyError

I'm using this library with django-autocomplete-light and searching/returning model instances that contain django-measurement fields is causing issues.

My model includes these fields (and many unrelated others):

    weight = MeasurementField(
        _('gross weight'),
        measurement=Weight,
        unit_choices=(('kg', 'kg'),),
        help_text=_('The weight of the contents in Kg, not including '
            'any packaging, etc.'
        )
    )
    volume = MeasurementField(
        _('volume'),
        measurement=Volume,
        unit_choices=(('cubic_meter', _('cubic meter')),),
        help_text=_('The volume in cubic meters (\u33a5).')
    )
    width = MeasurementField(
        _('width'),
        measurement=Distance,
        unit_choices=(('centimeter', _('centimeter')),),
        help_text=_('The width of the product in centimeters.')
    )
    height = MeasurementField(
        _('height'),
        measurement=Distance,
        unit_choices=(('centimeter', _('centimeter')),),
        help_text=_('The height of the product in centimeters.')
    )
    depth = MeasurementField(
        _('depth'),
        measurement=Distance,
        unit_choices=(('centimeter', _('centimeter')),),
        help_text=_('The depth of the product in centimeters.')
    )

When I try to test the models, e.g.

from random import randint

prod = Product()
prod.weight = Weight(kg=randint(1, 10))
prod.volume = Volume(cubic_meter=randint(1, 3))
prod.width = Distance(centimeter=randint(80, 100))
prod.height = Distance(centimeter=randint(80, 100))
prod.depth = Distance(centimeter=randint(60, 80))
prod.save()

this traceback appears:

File "/foo/lib/python2.7/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/foo/lib/python2.7/site-packages/django/views/generic/list.py", line 175, in get
    return self.render_to_response(context)
  File "/foo/lib/python2.7/site-packages/dal_select2/views.py", line 36, in render_to_response
    'results': self.get_results(context) + create_option,
  File "/foo/lib/python2.7/site-packages/dal_select2/views.py", line 19, in get_results
    } for result in context['object_list']
  File "/foo/lib/python2.7/site-packages/django/db/models/query.py", line 258, in __iter__
    self._fetch_all()
  File "/foo/lib/python2.7/site-packages/django/db/models/query.py", line 1074, in _fetch_all
    self._result_cache = list(self.iterator())
  File "/foo/lib/python2.7/site-packages/django/db/models/query.py", line 68, in __iter__
    for row in compiler.results_iter(results):
  File "/foo/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 808, in results_iter
    row = self.apply_converters(row, converters)
  File "/foo/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 792, in apply_converters
    value = converter(value, expression, self.connection, self.query.context)
  File "/foo/lib/python2.7/site-packages/django_measurement/models.py", line 90, in from_db_value
    original_unit=self.get_default_unit(),
  File "/foo/lib/python2.7/site-packages/django_measurement/utils.py", line 14, in get_measurement
    m.unit = original_unit
  File "/foo/lib/python2.7/site-packages/measurement/base.py", line 178, in unit
    unit = aliases[unit]
KeyError: None

Looking at the specific code it seems there's an obvious issue here because:

units = self.get_units()
unit = None
if value in self.UNITS:
    unit = value
elif value in aliases:
    unit = aliases[unit]  # unit = None....

Installation of 3.2.4 fails because of incorrect usage of setuptools (error: metadata-generation-failed)

Python version 3.8.15
Pipenv version 2022.12.19 (pip version 22.3.1)
Setuptools version 65.6.3

Traceback:

$ pipenv install --clear --keep-outdated --selective-upgrade django-measurement -vvv
Loading .env environment variables...
Installing django-measurement...
Writing supplied requirement line to temporary file: 'django-measurement'
Installing 'django-measurement'
$ /Users/alex.zagoro/venv/noya-4UEHQ2KQ/bin/python /usr/local/Cellar/pipenv/2022.12.19/libexec/lib/python3.11/site-packages/pipenv/patched/pip/__pip-runner__.py install --no-input --verbose --upgrade --upgrade-strategy=only-if-needed --exists-action=w -r /var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pipenv-np4m7i5o-requirements/pipenv-y7em9u0m-requirement.txt -i https://pypi.org/simple
Using source directory: '/Users/alex.zagoro/venv/noya-4UEHQ2KQ/src'
⠴ Installing package: django-measurement[31m[1mError: [0m An error occurred while installing [32mdjango-measurement[0m!
Error text: Using pip 22.3.1 from
/usr/local/Cellar/pipenv/2022.12.19/libexec/lib/python3.11/site-packages/pipenv/patched/pip (python
3.8)
Collecting django-measurement
  Using cached django_measurement-3.2.4-py2.py3-none-any.whl (7.2 kB)
Requirement already satisfied: django-appconf>=1.0.2 in
/Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages (from django-measurement->-r
/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pipenv-np4m7i5o-requirements/pipenv-y7em9u0m-require
ment.txt (line 1)) (1.0.4)
Requirement already satisfied: django>=2.2 in
/Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages (from django-measurement->-r
/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pipenv-np4m7i5o-requirements/pipenv-y7em9u0m-require
ment.txt (line 1)) (3.2.8)
Collecting measurement<4.0,>=1.6
  Using cached measurement-3.2.0.tar.gz (12 kB)
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'error'

[36m  Running command python setup.py egg_info
  /Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages/setuptools/config/setupcfg.py:508
: SetuptoolsDeprecationWarning: The license_file parameter is deprecated, use license_files instead.
    warnings.warn(msg, warning_class)
  /Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages/setuptools/installer.py:27:
SetuptoolsDeprecationWarning: setuptools.installer is deprecated. Requirements should be satisfied by
a PEP 517 installer.
    warnings.warn(
  Traceback (most recent call last):
    File "<string>", line 2, in <module>
    File "<pip-setuptools-caller>", line 34, in <module>
    File
"/private/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pip-install-0ik4ruc1/measurement_ceca7db089
394f61b736dfea8cfd7884/setup.py", line 4, in <module>
      setup(use_scm_version=True)
    File "/Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages/setuptools/__init__.py",
line 86, in setup
      _install_setup_requires(attrs)
    File "/Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages/setuptools/__init__.py",
line 80, in _install_setup_requires
      dist.fetch_build_eggs(dist.setup_requires)
    File "/Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages/setuptools/dist.py", line
874, in fetch_build_eggs
      resolved_dists = pkg_resources.working_set.resolve(
    File
"/Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages/pkg_resources/__init__.py", line
800, in resolve
      raise VersionConflict(dist, req).with_context(dependent_req)
  pkg_resources.ContextualVersionConflict: (sphinxcontrib.applehelp 1.0.3
(/private/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pip-install-0ik4ruc1/measurement_ceca7db089
394f61b736dfea8cfd7884/.eggs/sphinxcontrib.applehelp-1.0.3-py3.8.egg),
Requirement.parse('sphinxcontrib-applehelp'), {'sphinx'})
  error: subprocess-exited-with-error

  × python setup.py egg_info did not run successfully.
  │ exit code: 1
  ╰─> See above for output.

  note: This error originates from a subprocess, and is likely not a problem with pip.
  full command: /Users/alex.zagoro/venv/noya-4UEHQ2KQ/bin/python -c '
  exec(compile('"'"''"'"''"'"'
  # This is <pip-setuptools-caller> -- a caller that pip uses to run setup.py
  #
  # - It imports setuptools before invoking setup.py, to enable projects that directly
  #   import from `distutils.core` to work with newer packaging standards.
  # - It provides a clear error message when setuptools is not installed.
  # - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so
  #   setuptools doesn'"'"'t think the script is `-c`. This avoids the following warning:
  #     manifest_maker: standard file '"'"'-c'"'"' not found".
  # - It generates a shim setup.py, for handling setup.cfg-only projects.
  import os, sys, tokenize

  try:
      import setuptools
  except ImportError as error:
      print(
          "ERROR: Can not execute `setup.py` since setuptools is not available in "
          "the build environment.",
          file=sys.stderr,
      )
      sys.exit(1)

  __file__ = %r
  sys.argv[0] = __file__

  if os.path.exists(__file__):
      filename = __file__
      with tokenize.open(__file__) as f:
          setup_py_code = f.read()
  else:
      filename = "<auto-generated setuptools caller>"
      setup_py_code = "from setuptools import setup; setup()"

  exec(compile(setup_py_code, filename, "exec"))
  '"'"''"'"''"'"' %
('"'"'/private/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pip-install-0ik4ruc1/measurement_ceca7
db089394f61b736dfea8cfd7884/setup.py'"'"',), "<pip-setuptools-caller>", "exec"))' egg_info --egg-base
/private/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pip-pip-egg-info-yrq15d5v
  cwd:
/private/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pip-install-0ik4ruc1/measurement_ceca7db0893
94f61b736dfea8cfd7884/
error: metadata-generation-failed

× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
[0m
[36mUsing pip 22.3.1 from
/usr/local/Cellar/pipenv/2022.12.19/libexec/lib/python3.11/site-packages/pipenv/patched/pip (python
3.8)
Collecting django-measurement
  Using cached django_measurement-3.2.4-py2.py3-none-any.whl (7.2 kB)
Requirement already satisfied: django-appconf>=1.0.2 in
/Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages (from django-measurement->-r
/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pipenv-np4m7i5o-requirements/pipenv-y7em9u0m-require
ment.txt (line 1)) (1.0.4)
Requirement already satisfied: django>=2.2 in
/Users/alex.zagoro/venv/noya-4UEHQ2KQ/lib/python3.8/site-packages (from django-measurement->-r
/var/folders/01/c2gzvfh566b07_yvphkhv7fw0000gn/T/pipenv-np4m7i5o-requirements/pipenv-y7em9u0m-require
ment.txt (line 1)) (3.2.8)
Collecting measurement<4.0,>=1.6
  Using cached measurement-3.2.0.tar.gz (12 kB)
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'error'
[0m
This is likely caused by a bug in [32mdjango-measurement[0m. Report this to its maintainers.
✘ Installation Failed

Manual `measurement` dependency must now be specified when installing on Python 2.x

Just a note that measurement has now published version 3.0.0 which drops support for Python 2.x. That library is referenced as a dependency of django-measurement using the specification measurement>=1.6. This means that in Python 2.x environments installation of django-measurement will now fail, since measurement 3.0.0 will be selected, and 3.0.0 includes a dependency on a version of sphinx that requires Python >=3.5 for installation.

A workaround I found for this is to add measurement<3.0.0 to your requirements.txt or setup.py file in addition to django-measurement. This ensures the 2.x-compatible version of measurement is resolved as a dependency when installing django-measurement.

Hope that helps someone else running into this issue. Thanks for a great package!

Form fields are using wrong default unit

This may be related to #30 but I'm not sure. That issue said it was related to the inclusion of Bootstrap 3. I was using Bootstrap 4 and having the same issue. I decided to make a barebones version of a form without any bootstrapping or additional funny stuff and I have the same problem. My quick and dirty code is available here: https://github.com/MidasJade/beer_sample. It's probably something stupid I'm doing but I cannot figure it out.

For the quantity field in my form, no matter what type I use when I create it, it displays ounces in my list view and detail view, but displays grams in the update view. Based on this from the docs "Note that although the original unit specified is stored for display, that the unit is abstracted to the measure’s standard unit for storage and comparison" I'm assuming whatever was used to create it or update it should be what is displayed, right?

MEASURE_OVERRIDES not implemented in latest versions

The MEASURE_OVERRIDES setting does not appear to be implemented in the latest versions meaning custom measurements are broken.

Patch in my fork uses earlier version code to get it going again, not really tested yet.

Default value set to 0 returns an int instead of measurement instance

Given that I have a field:

from django_measurement.models import MeasurementField
from measurement.measures import Mass


class Product(models.Model):
    weight = MeasurementField(measurement=Mass, default=0)

I'd expect the default value to be set to Mass(any_unit=0) instead of 0 as an int.

In [5]: Product.objects.create().weight
Out[5]: 0

Form fields are using wrong default unit (always using STANDARD_UNIT)

I've set up my form like this:

class ThingForm(forms.ModelForm):

    height = MeasurementField(
        measurement=Distance,
        unit_choices=(('inch', 'in'), ('cm', 'cm'), ('feet', 'ft'), ('m', 'm')),
    )
    diameter = MeasurementField(
        measurement=Distance,
        unit_choices=(('inch', 'in'), ('cm', 'cm'), ('feet', 'ft'), ('m', 'm')),
    )

The form recognizes unit_choices, as those are the choices I get, but it defaults to meters instead of inches. In django_measurements/models.py, it seems like the method MeasurementField.get_default_unit() should return inch, but the if unit_choices never evaluates as true, and self.widget_args['unit_choices'] seems to be empty no matter what.

I'm using Python 3.5 and Django 1.9.

Allow fields to be optional i.e Null/Blank

I want to create measurement fields as optional with default value set to Null. As measurement field extends from FloatField which cannot be set to null=True or blank=True but instead to be a float value
If user don't set a value, i don't want to set some default float value or 0 or any other default value number.

any way to handle empty values?

Update Docs

Inconsistent references to from django_measurement.forms import MeasurementField
in github-docs and rtd-page.
Both link to different and wrong modules.
Be happy to provide pullrequest, if this is a yes-set.

Setting Form.initial for MeasurementField

Hi,
I have a question regarding on how to set initial value for fields in the form (generated via django's ModelForm).
Conventional way of doing that would be giving Form.initial a dictionary of keys vs initial values. That however does not work for MeasurementFields. So what would be your suggestion?
Kind Regards,
Onur

Customizing the form unit choices

Thanks for this project, it seems to be really useful! I've spend some time trying to get started with it. I managed to create a form and render it in a template like this:

# models.py
from django.db import models
from django_measurement.models import MeasurementField
from measurement.measures import Volume

class Entry(models.Model):
    name = models.CharField(max_length=255, verbose_name='Beverage')
    volume = MeasurementField(measurement=Volume)

# forms.py
from django import forms
from .models import Entry

class EntryForm(forms.ModelForm):

    class Meta:
        model = Entry
        fields = ["name", "volume"]

I was trying to modify the units displayed in the dropdown like shown in the documentation:

# forms.py
from measurement.measures import Volume
from django_measurement.models import MeasurementField

class BeerForm(forms.Form):

    volume = MeasurementField(
        measurement=Volume,
        unit_choices=(("l","l"), ("oz","oz")),
    )

However when playing with this form in the django shell, it seems there are no fields:

from entries.forms import BeerForm
b = BeerForm()
b.fields
>> {}
b.as_table()
>> ''

I tried different things, using MeasurementWidget or modifying the widget via the widget property in the Meta class in the ModelForm approach.

Am I missing something here? Any advice welcome, thanks!

django = "~=3.1.0"
django-measurement = "==3.2.3"
python_version = "3.8"

Cannot serialize: Mass(kg=80) when making migrations

Model:
`
from measurement.measures import Weight

goal_weight = MeasurementField(measurement=Weight, null=True, blank=True, default=Weight(kg=80))
`

python manage.py makemigrations:
ValueError: Cannot serialize: Mass(kg=80.0) There are some values Django cannot serialize into migration files. For more, see https://docs.djangoproject.com/en/3.1/topics/migrations/#migration-serializing

using django-measurement version 3.2.3, measurement version 3.2.0, django version 3.1.3

Throw warning for naive measure

Currently you can set the set a field value using a float. Be default it's assumed that the float is representing the default unit the value is getting saved.

We should throw a warning, about this behaviour and encourage users to set explicit measures.

Any i18n options?

Would like to ask if are there any options for locale? Or how would the package behave with it in Django?

Serialization of Validators does not work

When I use the code examples from the unit tests that use MinValueValidator and MaxValueValidator , such as:

    measurement_weight = MeasurementField(
        measurement=measures.Weight,
        validators=[
            MinValueValidator(measures.Weight(kg=1.0)),
            MaxValueValidator(measures.Weight(kg=3.0))
        ],
        blank=True, null=True,
    )

From here.

Upon creating the migration I receive the error:

  File "manage.py", line 29, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 316, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 353, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/makemigrations.py", line 184, in handle
    self.write_migration_files(changes)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/makemigrations.py", line 222, in write_migration_files
    migration_string = writer.as_string()
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/writer.py", line 151, in as_string
    operation_string, operation_imports = OperationWriter(operation).serialize()
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/writer.py", line 110, in serialize
    _write(arg_name, arg_value)
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/writer.py", line 62, in _write
    arg_string, arg_imports = MigrationWriter.serialize(item)
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/writer.py", line 279, in serialize
    return serializer_factory(value).serialize()
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/serializer.py", line 37, in serialize
    item_string, item_imports = serializer_factory(item).serialize()
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/serializer.py", line 197, in serialize
    return self.serialize_deconstructed(path, args, kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/serializer.py", line 85, in serialize_deconstructed
    arg_string, arg_imports = serializer_factory(arg).serialize()
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/serializer.py", line 37, in serialize
    item_string, item_imports = serializer_factory(item).serialize()
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/serializer.py", line 102, in serialize
    return self.serialize_deconstructed(*self.value.deconstruct())
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/serializer.py", line 81, in serialize_deconstructed
    arg_string, arg_imports = serializer_factory(arg).serialize()
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/serializer.py", line 353, in serializer_factory
    "topics/migrations/#migration-serializing" % (value, get_docs_version())
ValueError: Cannot serialize: Mass(kg=1.0)
There are some values Django cannot serialize into migration files.
For more, see https://docs.djangoproject.com/en/2.1/topics/migrations/#migration-serializing

Using Django version 2.1.7

Why not provide a model field per measure type?

It seems that the design of django-measurement is to provide a single model field, MeasurementField, which is used for all measure types (distance, weight, volume, etc). This requires the MeasurementField to add a third database column to the model's table (in addition to unit and value) to store the name of the measure type.

I suppose this flexibility (to store a different measure type in the same measurement field in different rows) could be useful in some unusual cases, but it seems to me that in most common use cases this flexibility is actually a negative, as I'd prefer to ensure that, for instance, only Distance can be stored in a height field, and in these common cases the additional database column is useless dead weight.

Would you accept a pull request to support measure-specific model fields (e.g. WeightField, DistanceField, VolumeField, etc), which would require only two database columns instead of three?

Compatibility with Django 3

Since library Six was removed in Django 3.x the measurement library is not longer working due to this dependency

from django_measurement.models import MeasurementField
  File "\lib\site-packages\django_measurement\models.py", line 9, in <module>
    from . import forms
  File "\lib\site-packages\django_measurement\forms.py", line 8, in <module>
    from django_measurement.conf import settings
  File "\lib\site-packages\django_measurement\conf.py", line 2, in <module>
    from appconf import AppConf
  File "\lib\site-packages\appconf\__init__.py", line 2, in <module>
    from .base import AppConf  
File "\lib\site-packages\appconf\base.py", line 4, in <module>
    from django.utils import six
ImportError: cannot import name 'six' from 'django.utils' (\lib\site-packages\django\utils\__init__.py)

RuntimeError: maximum recursion depth exceeded

Hi I encountered the following error. Seems you have a little loop in there.

  File "django_measurement/admin.py", line 88, in get_fieldsets
    form = self.get_form(request, obj)(instance=obj)
  File "django/contrib/admin/options.py", line 503, in get_form
    fields = flatten_fieldsets(self.get_fieldsets(request, obj))

BTW: We're talking Python 2.7 and Django 1.6.1 here.

I haven't really looked deep enough into the code yet to fix it myself, plus there isn't a doc-string to tell me what the method should be doing.

Inline Formsets With Extra Rows Triggering has_changed

Curious if you've successfully used a MeasurementField with inline formsets? I can make a quick sample project if you like, but the TLDR version is that an extra row or an added row to an inline formset, where the row contains a MeasurementField, triggers has_changed (I'm thinking maybe when the dropdown is populated?) so the submitted form doesn't validate properly if it contains other required fields.

Bug in Mass and Distance classes

Hey, it happens only with particular units and values. I get very strange rounding:
image

For now I noticed problem with inch, lb and it happens only with value = 3

Using measurement and unit as inline input group in form?

Hello,

I'm trying to achieve an inline input group in a form in Django. I've tried for days to get the unit_choices to show up in a way that would work for this, but I'm still struggling, so I'm wondering if this is even possible.

As you can see I have a MeasureBase class "Height" that takes three units.

I have attached a mockup of what I envision...

Thanks for django-measurement and thanks in advance for any advice you may have!

input_group
input_group2

Serializer gives float() argument must be a string or a number, not 'Distance'

I have a few MeasurementFields set up in my Django model. My serializer fails with the above message. What am I missing? How can I use MeasurementFields with the Django Rest Framework serializers?

The traceback looks like below:

Traceback (most recent call last):
  File "/home/lib64/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/lib64/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/lib64/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/lib64/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/lib64/python3.6/site-packages/django/views/generic/base.py", line 71, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/lib64/python3.6/site-packages/rest_framework/views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "/home/lib64/python3.6/site-packages/rest_framework/views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/lib64/python3.6/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
    raise exc
  File "/home/lib64/python3.6/site-packages/rest_framework/views.py", line 502, in dispatch
    response = handler(request, *args, **kwargs)
  File "/home/o/barcodes/views.py", line 151, in get
    return Response(serializer.data)
  File "/home/lib64/python3.6/site-packages/rest_framework/serializers.py", line 562, in data
    ret = super().data
  File "/home/lib64/python3.6/site-packages/rest_framework/serializers.py", line 260, in data
    self._data = self.to_representation(self.instance)
  File "/home/lib64/python3.6/site-packages/rest_framework/serializers.py", line 529, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/home/lib64/python3.6/site-packages/rest_framework/serializers.py", line 678, in to_representation
    self.child.to_representation(item) for item in iterable
  File "/home/lib64/python3.6/site-packages/rest_framework/serializers.py", line 678, in <listcomp>
    self.child.to_representation(item) for item in iterable
  File "/home/lib64/python3.6/site-packages/rest_framework/serializers.py", line 529, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/home/lib64/python3.6/site-packages/rest_framework/fields.py", line 1030, in to_representation
    return float(value)

Unable to save through Django admin

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)

Docs issue(?): django_measurement.measures doesn't exist

In the docs it says to use:

from django_measurement.models import MeasurementField
from django_measurement.measures import Weight,Volume

but django_measurement only contains models, utils and forms. The weight/volume etc. come from measurement.measures.

so shouldn't this be:

from django_measurement.models import MeasurementField
from measurement.measures import Weight,Volume

Or am I doing something wrong?

Rounding error

Thanks for this fine package.

I'm having a small issue, however, with the Temperature. When I enter 38,4 degrees Celsius, it gets saved as 38,39999999999998 degrees Celsius, which doesn't look so nice.

Is there a way to solve this?

Django admin doesn't show Zero time values

If a time value is zero then it shows as empty in Django Admin. This is an issue while updating the object, I have to enter zero value for Time field every time even though I was updating other fields of model.

instructor_time_required = MeasurementField(measurement=Time, unit_choices=[ ['min', 'min'], ['hr', 'hr'] ], help_text="Total time per instructor that will be spent on delivering this unit", validators=[MinValueValidator(Time(min=0))], )

As field is non null, I have to enter Zero every time
image

Actual value of the field is Zero as I can see in pgAdmin
image

Probably issue is there for other measures as well, didn't check.

django-Measurement does not have a django rest framework serializer field

Hi. I've wrote a serializer field to use django-measurement with django rest framework beacuse i could'n find it nowhere.
Something near this was discussed here.
(I'm not sure this is the best way to share this... let me know).

MeasurementSerializerField.py:

import decimal
from rest_framework import serializers

def is_valid_unit(unit_to_validate, measurement_class):
    return unit_to_validate in measurement_class.get_units()

def is_valid_decimal(value_to_validate):
    return decimal.Decimal(value_to_validate)


class MeasurementSerializerField(serializers.Field):
    '''
    Basic generic serializer field for Django REST Framework integration for django-measurement model fields.
    https://github.com/coddingtonbear/django-measurement
    '''
    
    def __init__(self, measurement_class, *args, **kwargs):
        super(MeasurementSerializerField, self).__init__(*args, **kwargs)
        self.measurement_class = measurement_class

    def to_representation(self, obj):
        return {
            'unit': obj.unit,
            'value': obj.value
        }
    
    default_error_messages = {
        'invalid_unit': 'Invalid unit. {invalid_unit} is not a valid {measurement_class.__name__} unit',
        'invalid_value': 'Invalid value. {invalid_value} is not a valid {measurement_class.__name__} value',
    }
    def to_internal_value(self, data):
        if not is_valid_unit(data['unit'], self.measurement_class):
            self.fail(
                'invalid_unit',
                invalid_unit=data['unit'],
                measurement_class=self.measurement_class
            )

        if not is_valid_decimal(data['value']):
            self.fail(
                'invalid_value',
                invalid_value=data['value'],
                measurement_class=self.measurement_class
            )

        return self.measurement_class(**{data['unit']: data['value']})

And the implementation could be like in ModelWithMeasurementsSerializer.py

# all imports and so

class ModelWithMeasurementsSerializer(serializers.ModelSerializer):
    width = MeasurementSerializerField(measurement_class=Distance, required=False)
    height = MeasurementSerializerField(measurement_class=Distance, required=False)
    length = MeasurementSerializerField(measurement_class=Distance, required=False)
    weight = MeasurementSerializerField(measurement_class=Weight, required=False)

    class Meta:
        model = ModelWithMeasurements
        fields = '__all__'

Perhaps something like that could be included in the library.

Cannot deserialize measurement fields

Steps

  1. Having a model with measurement data
  2. Exporting the database data using ./manage.py dumpdata [app[.model]] -o output.json
  3. Loading the fixture data back into the database using ./manage.py loaddata output.json

Error Stack

  File "python3.7/site-packages/django/core/management/commands/loaddata.py", line 72, in handle
    self.loaddata(fixture_labels)
  File "python3.7/site-packages/django/core/management/commands/loaddata.py", line 114, in loaddata
    self.load_label(fixture_label)
  File "python3.7/site-packages/django/core/management/commands/loaddata.py", line 172, in load_label
    for obj in objects:
  File "python3.7/site-packages/django/core/serializers/json.py", line 69, in Deserializer
    yield from PythonDeserializer(objects, **options)
  File "python3.7/site-packages/django/core/serializers/python.py", line 145, in Deserializer
    raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
django.core.serializers.base.DeserializationError: Problem installing fixture 'dump.json': ["'1.0 kg' value must be a float."]: (myapp.mymodel:pk=7) field_value was '1.0 kg'

MeasurementFormMixin

What's the MeasurementFormMixin exactly for? I don't think it's really needed, as in there's a more django-like way to solve this.

If you tell me what it does I'd willing to implement it, because it does crash if you have another ForeignKey in your model that is blank.

Model has no Reversed ForeignKey

File "django_measurement/forms.py", line 63, in __init__
codingjoe
   measurements = inspect.getmembers(instance, lambda x: isinstance(x, django_measurement.base.MeasureBase) or isinstance(x, django.contrib.gis.measure.MeasureBase) or isinstance(x, MeasurementField))

This lambda seems to follow reverse relations as well.

Modelserializer in django rest_framework serializes MeasurementField as FloatField

hi,

I have the following field in my model:
MeasurementField(measurement=Weight, unit_choices=(('kg','kg'),('lb','lb'),))

which serializes as a FloatField() in django rest framework using serializers.ModelSerializer. This FloatField() then does not accept a Mass() object so I land on a TypeError.

Anyone with an idea how to rewrite the serializers to_represantation and to_internal_value to handle this error?
I tried this which works for the representation part:

 def to_representation(self, obj):
        return {
            'weight': obj.weight.value,
            'unit': obj.weight.unit}

But I cannot get the to_internal_value to work. Besides, there are other fields in the model which I have to rewrite if I use this approach. Thanks in advance for any suggestion!

Could it be an enhancement to include a serializerField in the MeasurementField definition?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.