File: README.md

package info (click to toggle)
python-django-pint 0.7.3-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 432 kB
  • sloc: python: 1,531; makefile: 28; sh: 12
file content (162 lines) | stat: -rw-r--r-- 7,462 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# Django Quantity Field


A Small django field extension allowing you to store quantities in certain units and perform conversions easily. Uses [pint](https://github.com/hgrecco/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 >= 3.2, and python 3.8/3.9/3.10/3.11

Tested with the following combinations:
* Django 3.2 (Python 3.8, 3.9, 3.10, 3.11)
* Django 4.2 (Python 3.8, 3.9, 3.10, 3.11)

## 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_bootle_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](https://pint.readthedocs.io/en/latest/tutorial.html#using-pint-in-your-projects)
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](https://github.com/pyenv/pyenv) to do so.

Furthermore, you need to install [tox](https://tox.wiki/en/latest/) and [pre-commit](https://pre-commit.com/) 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](https://pypa.github.io/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](https://docs.github.com/get-started/quickstart/contributing-to-projects))
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](https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork).

### 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](https://stackoverflow.com/a/47078951/3813064) 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](https://endoflife.date/python) and [Django](https://endoflife.date/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
 - `setup.cfg`: For usage with pip and displaying it in PyPa
 - `.github/workflows/test.yaml`: For the CI/CD Definition