Skip to main content

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, "metric_ton")
>>> bale.weight.magnitude
1.2
>>> bale.weight.units
Unit("metric_ton")
>>> bale.weight.to('kilogram')
Quantity(1200.0, "kilogram")
>>> bale.weight.to('pound')  # doctest: +ELLIPSIS
Quantity(2645.5..., "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 = HayBale.objects.last()
>>> bale.weight  # doctest: +ELLIPSIS
Quantity(0.2267..., "metric_ton")

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.

>>> from django import forms
>>> from quantityfield.fields import QuantityFormField
>>> class HayBaleForm(forms.Form):
...     weight = QuantityFormField(base_units='gram', unit_choices=['gram', 'ounce', 'milligram'])
>>> form = HayBaleForm(data={'weight_0': '100', 'weight_1': 'gram'})
>>> form.is_valid()
True
>>> form.cleaned_data['weight']
Quantity(100.0, "gram")

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.

>>> from quantityfield.units import ureg
>>> Quantity = ureg.Quantity
>>> bale = HayBale.objects.create(weight=0.3)
>>> HayBale.objects.filter(weight__lt=Quantity(2000 * ureg.pound)).count()
1

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 Docker — the tests spin up a PostgreSQL container automatically via testcontainers. No separate database installation is required.

  1. Install uv
  2. Fork django-pint and clone your fork (see Tutorial)
  3. Change into the repo: cd django-pint
  4. Install all development dependencies: uv sync
  5. Activate pre-commit hooks: uv run pre-commit install
  6. Check that all linters pass: uv run pre-commit run --all-files
  7. Run the full test suite: nox

Congratulations! You have successfully set up and tested the upstream version of django-pint.

Now you can work on your feature branch and test your changes with nox. Your code will be automatically linted and formatted by pre-commit when you commit. If it fails, add the formatted changes and commit again.

Once you are done, create a pull request.

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
  • noxfile.py: For local testing
  • pyproject.toml: For usage with pip and displaying it in PyPi
  • .github/workflows/test.yaml: For the CI/CD Definition

Metadata

Release files for django-pint 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-pint 1.1.0
File Size Uploaded Provenance Actions
django_pint-1.1.0.tar.gz 33.1 kB With provenance Details for django_pint-1.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-pint 1.1.0
File Interpreter ABI Platform Actions
django_pint-1.1.0-py3-none-any.whl Python 3 none any Details for django_pint-1.1.0-py3-none-any.whl

Total release size: 45.8 kB

Release files / django_pint-1.1.0.tar.gz

Download URL django_pint-1.1.0.tar.gz
Size 33.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0d7c556d6962ca3d450d1b5f331f85cba9a2f68c47915d7ad97c46bbe1efec46
BLAKE2b-256 checksum
How to use checksums
3de12ba069c35e2c48927b5def113602be93aa75431a338077dc7efc6df5b388
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / django_pint-1.1.0-py3-none-any.whl

Download URL django_pint-1.1.0-py3-none-any.whl
Size 12.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
80d78ece47cf3cd23c0d422792d5f7cb503b49a1c4ab482a02aa4100fc748919
BLAKE2b-256 checksum
How to use checksums
f00ce36ce54518d791a57f0678f53031b8704b0d66fcb46561f176a475c51da3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Security for django-pint 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_pint-1.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page