Skip to main content

Quantity Field for Django using pint library for automated unit conversions

Project description

Build Status codecov PyPI Downloads Python Versions PyPI Version Project Status Wheel Build Code Style Black pre-commit pre-commit.ci status License: MIT Documentation Status

Django Quantity Field

A Small django field extension allowing you to store quantities in certain units and perform conversions easily. Uses pint behind the scenes. Also contains a form field class and form widget that allows a user to choose alternative units to input data. The cleaned_data will output the value in the base_units defined for the field, eg: you specify you want to store a value in grams but will allow users to input either grams or ounces.

Help wanted

I am currently not working with Django anymore. Therefore the Maintenance of this project is not a priority for me anymore. If there is anybody that could imagine helping out maintaining the project, send me a mail.

Compatibility

Requires django >= 5.2, and python 3.10/3.11/3.12/3.13/3.14

Tested with the following combinations:

  • Django 5.2 (Python 3.10, 3.11, 3.12, 3.13, 3.14)
  • Django 6.0 (Python 3.12, 3.13, 3.14)

Installation

pip install django-pint

Simple Example

Best way to illustrate is with an example

# app/models.py

from django.db import models
from quantityfield.fields import QuantityField

class HayBale(models.Model):
    weight = QuantityField('tonne')

Quantities are stored as float (Django FloatField) and retrieved like any other field

>> bale = HayBale.objects.create(weight=1.2)
>> bale = HayBale.objects.first()
>> bale.weight
<Quantity(1.2, 'tonne')>
>> bale.weight.magnitude
1.2
>> bale.weight.units
'tonne'
>> bale.weight.to('kilogram')
<Quantity(1200, 'kilogram')>
>> bale.weight.to('pound')
<Quantity(2645.55, 'pound')>

If your base unit is atomic (i.e. can be represented by an integer), you may also use IntegerQuantityField and BigIntegerQuantityField.

If you prefer exact units you can use the DecimalQuantityField

You can also pass Quantity objects to be stored in models. These are automatically converted to the units defined for the field ( but can be converted to something else when retrieved of course ).

>> from quantityfield.units import ureg
>> Quantity = ureg.Quantity
>> pounds = Quantity(500 * ureg.pound)
>> bale = HayBale.objects.create(weight=pounds)
>> bale.weight
<Quantity(0.226796, 'tonne')>

Use the inbuilt form field and widget to allow input of quantity values in different units

from quantityfield.fields import QuantityFormField

class HayBaleForm(forms.Form):
    weight = QuantityFormField(base_units='gram', unit_choices=['gram', 'ounce', 'milligram'])

The form will render a float input and a select widget to choose the units. Whenever cleaned_data is presented from the above form the weight field value will be a Quantity with the units set to grams (values are converted from the units input by the user). You also can add the unit_choices directly to the ModelField. It will be propagated correctly.

For comparative lookups, query values will be coerced into the correct units when comparing values, this means that comparing 1 ounce to 1 tonne should yield the correct results.

less_than_a_tonne = HayBale.objects.filter(weight__lt=Quantity(2000 * ureg.pound))

You can also use a custom Pint unit registry in your project settings.py

# project/settings.py

from pint import UnitRegistry

# django-pint will set the DJANGO_PINT_UNIT_REGISTER automatically
# as application_registry
DJANGO_PINT_UNIT_REGISTER = UnitRegistry('your_units.txt')
DJANGO_PINT_UNIT_REGISTER.define('beer_bottle_weight = 0.8 * kg = beer')

# app/models.py

class HayBale(models.Model):
    # now you can use your custom units in your models
    custom_unit = QuantityField('beer')

Note: As the documentation from pint states quite clearly: For each project there should be only one unit registry. Please note that if you change the unit registry for an already created project with data in a database, you could invalidate your data! So be sure you know what you are doing! Still only adding units should be okay.

Development

Preparation

You need to install all Python Version that django-pint is compatible with. In a *nix environment you best could use pyenv to do so.

Furthermore, you need to install tox and pre-commit to lint and test.

You also need docker as our tests require a postgres database to run. We don't use SQL lite as some bugs only occurred using a proper database.

I recommend using pipx to install them.

  1. Install pipx (see pipx documentation), i.e. with python3 -m pip install --user pipx && python3 -m pipx ensurepath
  2. Install pre-commit running pipx install pre-commit
  3. Install tox running pipx install tox
  4. Install the tox-docker plugin pipx inject tox tox-docker
  5. Fork django-pint and clone your fork (see Tutorial)
  6. Change into the repo cd django-pint
  7. Activate pre-commit for the repo running pre-commit install
  8. Check that all linter run fine with the cloned version by running pre-commit run --all-files
  9. Check that all tests succeed by running tox

Congratulation you successfully cloned and tested the upstream version of django-pint.

Now you can work on your feature branch and test your changes using tox. Your code will be automatically linted and formatted by pre-commit if you commit your changes. If it fails, simply add all changes and try again. If this doesn't help look at the output of your git commit command.

Once you are done, create a pull request.

Local development environment with Docker

To run a local development environment with Docker you need to run the following steps: This is helpful if you have troubles installing postgresql or psycopg2-binary.

  1. git clone your fork
  2. run cp .env.example .env
  3. edit .env file and change it with your credentials ( the postgres host should match the service name in docker-file so you can use "postgres" )
  4. run cp tests/local.py.docker-example tests/local.py
  5. run docker-compose up in the root folder, this should build and start 2 containers, one for postgres and the other one python dependencies. Note you have to be in the docker group for this to work.
  6. open a new terminal and run docker-compose exec app bash, this should open a ssh console in the docker container
  7. you can run pytest inside the container to see the result of the tests.

Updating the package

Python and Django major versions have defined EOL. To reduce the maintenance burden and encourage users to use version still receiving security updates any django-pint update should match all and only these version of Python and Django that are supported. Updating these dependencies have to be done in multiple places:

  • README.md: Describing it to end users
  • tox.ini: For local testing
  • pyproject.toml: For usage with pip and displaying it in PyPi
  • .github/workflows/test.yaml: For the CI/CD Definition

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_pint-1.0.4.tar.gz (42.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_pint-1.0.4-py3-none-any.whl (13.1 kB view details)

Uploaded Python 3

File details

Details for the file django_pint-1.0.4.tar.gz.

File metadata

  • Download URL: django_pint-1.0.4.tar.gz
  • Upload date:
  • Size: 42.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_pint-1.0.4.tar.gz
Algorithm Hash digest
SHA256 da1ae98910b4156cdb5bb1f9590bf1d12fd590fef1a864722d9b941265bd1a34
MD5 ee203e98794fa1cac816e51758e913cf
BLAKE2b-256 da2e8497b9248a7651318246e27c50d36334e773f17a8593bb8af22dce3f5b25

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_pint-1.0.4.tar.gz:

Publisher: publish-to-pypi.yml on CarliJoy/django-pint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_pint-1.0.4-py3-none-any.whl.

File metadata

  • Download URL: django_pint-1.0.4-py3-none-any.whl
  • Upload date:
  • Size: 13.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_pint-1.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 5b6776a87b3958732bbd01f75dcc117005b026dd6d436025e63d6adb68688d4f
MD5 a51664d683e274c2b99f1d5d81bea4c2
BLAKE2b-256 f8214d044187d02d83c95bc46c0c64e6e9f09c83409e927018efc2b794dc0ad6

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_pint-1.0.4-py3-none-any.whl:

Publisher: publish-to-pypi.yml on CarliJoy/django-pint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page