Django model field to allow storage of a distance (with units).
Django Distance Field
92% Unit Testing Coverage https://bitbucket.org/squarehost/django-distance-field.git
(C) 2018 Squarehost Ltd. http://www.squarehost.co.uk
Ian Shurmer (email@example.com)
What is it?
Django Distance Field is a simple extension to Django's GIS fields to allow registration of a distance/measurement field within a model. Data within this field can then be converted using Django's "D" objects, and filtered using standard Django queryset functionality.
It doesn't need a GIS enabled database or extension installed. It should work with Django version 1.7 and above.
What does that mean?
Put simply, you can add a distance field which allows the user to enter a measurement using a large variety of units. This distance will then be converted to a standard unit format (for example, metres), and stored in the database. The user's specified units are also stored, and when the measurement retrieved, automatically converted into these to be displayed.
Well, how about some psuedo-code? Here's how you might use the API:
In : from mymodels.model import ModelWithWidthHeight In : from distance import D In : inst = ModelWithWidthHeight( ) In : inst.width = "10m" In : inst.width Out: D(m=10.0) In : inst.height = "10in" In : inst.height Out: D(inch=10.0) In : inst.width > inst.height Out: True In : inst.height.m Out: 0.254
Is that it? Yawn...
Wait, there's more! You can also filter querysets directly using either D objects or strings, with all your usual Django API niceness:
In : from mymodels.model import ModelWithWidthHeight In : from distance import D In : ModelWithWidthHeight.objects.filter(width__lte="10m") Out: <QuerySet [<ModelWithWidthHeight: ModelWithWidthHeight object (1)>]> In : ModelWithWidthHeight.objects.filter(width__lt="10m") Out: <QuerySet > In : ModelWithWidthHeight.objects.filter(width__lte="1000cm") Out: <QuerySet [<ModelWithWidthHeight: ModelWithWidthHeight object (1)>]> In : ModelWithWidthHeight.objects.filter(width__lte="999cm") Out: <QuerySet > In : ModelWithWidthHeight.objects.filter(width__lte="1000cm", height__gt=D(inch=9)) Out: <QuerySet [<ModelWithWidthHeight: ModelWithWidthHeight object (1)>]>
Okay, that looks a little more useful. What about forms and widgets?
Using a DistanceField automatically results in a standard CharField being included within the form, BUT with relevant validators applied to ensure that the system recognises the units, and throws a ValidationError if not.
The field data is then automatically parsed to the D object and stored in the database accordingly.
What units do you recognise?
Along with Django's default units we have a couple of others thrown in (for example, Rack Units/U), meaning current support is as follows:
- Chain, Chain Benoit, Chain Sears, British Chain Benoit, British Chain Sears, British Chain Sears Truncated, Cm, British Ft, British Yd, Clarke Ft, Clarke Link, Fathom, Ft, German M, Gold Coast Ft, Indian Yd, Inch, Km, Link, Link Benoit, Link Sears, M, Mi, Mm, Nm, Nm Uk, Rod, Sears Yd, Survey Ft, Um, Yd, U
You can also add units if you so desire - simply call the distance.register_units method with your unit alias as keyword arguments, and the number of units in metres as the keyword value. For example:
In : import distance In : distance.register_units(my_unit=0.5, my_other_unit=2) In : distance.D(my_unit=10).m Out: 5.0 In : distance.D(my_unit=10).inch Out: 196.8503937007874 In : distance.D(my_other_unit=10).m Out: 20.0
You should probably do that somewhere like your app ready methods.
What about aliases? You say "inch", I say '"'
We have a variety of aliases already specified within the D class:
|british_chain_benoit||British chain (Benoit 1895 B)|
|british_chain_sears_truncated||British chain (Sears 1922 truncated)|
|british_chain_sears||British chain (Sears 1922)|
|british_ft||British foot (Sears 1922)|
|british_yd||British yard (Sears 1922)|
|german_m||German legal metre|
|gold_coast_ft||Gold Coast foot|
|nm_uk||Nautical Mile (UK)|
|survey_ft||US survey foot|
As we're not too picky, the aliases are case-insensitive.
My alias isn't there?
Well, as with units, you can add your own. Keyword argument keys should be your new alias, with the value the existing units:
In : import distance In : distance.register_aliases(feet="ft") In : distance.D(feet=10) Out: D(ft=10.0)
How does it work then?
When you create a DistanceField in your model, it also has a default unit (metres unless you change it through the unit kwarg). Any distances passed to this unit field are converted into this standard unit, before being saved into the database as a decimal in much the same way as a DecimalField.
But you said it will remember my units? How?
Glad you asked. Optionally, although if you don't add it we can't remember your units, for each DistanceField you add you should also add a DistanceUnitField, and tell your DistanceField about it. The DistanceUnitField is a simple CharField, which is automatically populated depending on the units specified in your DistanceField.
You don't need to worry about this field, simply creating it in your model and pointing the DistanceField to it is all you need to do. It's not editable, and you don't need to change it.
Okay, I'm sold. Well, sold enough to download and test an MIT-licensed library anyway. How do I use it?
You can install either directly via PyPi (pip install django-distance-field), or checkout from our Git repo: https://bitbucket.org/squarehost/django-distance-field.git
Usage is straightforward. As it's only a field, you don't need to add to your INSTALLED_APPS, although you can do so if you wish to run tests.
In your models.py file, create the DistanceField according to your requirements:
from distance import DistanceField, DistanceUnitField class ModelWithWidthHeight(models.Model): width = DistanceField(unit='m', unit_field='width_units') height = DistanceField(unit='in', unit_field='height_units') width_units = DistanceUnitField( ) height_units = DistanceUnitField( )
DistanceField will also respect standard Django DecimalField options, such as
decimal_places. Bear in mind that the field will actually be stored in the unit you specify, so you might want to change the max_digits and precision depending on your requirements.
Also, bearing in mind that your units may well be converted to all other weird and wonderful units, you may want a couple of extra decimal places to try and reduce the occurrence of any strange rounding errors.
unit is m (metres),
max_digits is 14, and
decimal_places is 6.
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
|Filename, size||File type||Python version||Upload date||Hashes|
|Filename, size django-distance-field-1.0.3.tar.gz (13.7 kB)||File type Source||Python version None||Upload date||Hashes View hashes|
Hashes for django-distance-field-1.0.3.tar.gz