Package: django-distance-field
Django Distance Field92% Unit Testing Coveragehttps://bitbucket.org/squarehost/django-distance-field.git(C) 2018 Squarehost Ltd.http://www.squarehost.co.ukIan Shurmer (ian@squarehost.co.uk)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.Eh?Well, how about some psuedo-code? Here's how you might use the API:In[1]:frommymodels.modelimportModelWithWidthHeightIn[2]:fromdistanceimportDIn[3]:inst=ModelWithWidthHeight()In[4]:inst.width="10m"In[5]:inst.widthOut[5]:D(m=10.0)In[6]:inst.height="10in"In[7]:inst.heightOut[7]:D(inch=10.0)In[8]:inst.width>inst.heightOut[8]:TrueIn[9]:inst.height.mOut[9]:0.254Is 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[1]:frommymodels.modelimportModelWithWidthHeightIn[2]:fromdistanceimportDIn[3]:ModelWithWidthHeight.objects.filter(width__lte="10m")Out[3]:<QuerySet[<ModelWithWidthHeight:ModelWithWidthHeightobject(1)>]>In[4]:ModelWithWidthHeight.objects.filter(width__lt="10m")Out[4]:<QuerySet[]>In[5]:ModelWithWidthHeight.objects.filter(width__lte="1000cm")Out[5]:<QuerySet[<ModelWithWidthHeight:ModelWithWidthHeightobject(1)>]>In[6]:ModelWithWidthHeight.objects.filter(width__lte="999cm")Out[6]:<QuerySet[]>In[7]:ModelWithWidthHeight.objects.filter(width__lte="1000cm",height__gt=D(inch=9))Out[7]:<QuerySet[<ModelWithWidthHeight:ModelWithWidthHeightobject(1)>]>Okay, that looks alittlemore useful. What about forms and widgets?Using a DistanceField automatically results in a standard CharField being included within the form,BUTwith 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, UYou 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 unitsin metresas the keyword value. For example:In[1]:importdistanceIn[2]:distance.register_units(my_unit=0.5,my_other_unit=2)In[3]:distance.D(my_unit=10).mOut[3]:5.0In[4]:distance.D(my_unit=10).inchOut[4]:196.8503937007874In[5]:distance.D(my_other_unit=10).mOut[5]:20.0You 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:Actual UnitAliasbritish_chain_benoitBritish chain (Benoit 1895 B)british_chain_sears_truncatedBritish chain (Sears 1922 truncated)british_chain_searsBritish chain (Sears 1922)british_ftBritish foot (Sears 1922)british_ftBritish footbritish_ydBritish yard (Sears 1922)british_ydBritish yardchain_benoitChain (Benoit)chain_searsChain (Sears)clarke_ftClarke's Footclarke_linkClarke's linkcmcentimeterft'ftFoot (International)ftfootgerman_mGerman legal metregold_coast_ftGold Coast footinch"inchinchesinchinindian_ydIndian yardindian_ydYard (Indian)kmkilometerkmkilometrelink_benoitLink (Benoit)link_searsLink (Sears)mimilemmmillimetermmmillimetremmetermmetrenm_ukNautical Mile (UK)nmNautical Milesears_ydYard (Sears)survey_ftU.S. Footsurvey_ftUS survey footummicrometerummicrometreuruydyardAs we're nottoopicky, 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[1]:importdistanceIn[2]:distance.register_aliases(feet="ft")In[3]:distance.D(feet=10)Out[3]: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.gitUsage 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:fromdistanceimportDistanceField,DistanceUnitFieldclassModelWithWidthHeight(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 asblank,null,max_digits, anddecimal_places. Bear in mind that the field will actually be stored in theunityou 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.Defaultunitis m (metres),max_digitsis 14, anddecimal_placesis 6.