94

I want to store my users location using longitude and latitude, at the moment this comes from Google Maps, but I will be using GeoDango and some point to work out distances between to points also.

However, my first confusion is which field in Django I should be using to store the longitude and latitude values? The information I'm getting is conflicting.

The official documentation uses a FloatField https://docs.djangoproject.com/en/dev/ref/contrib/gis/tutorial/#geographic-models

lon = models.FloatField()
lat = models.FloatField()

Where almost every answer on stackoverflow shows a DecimalField

long = models.DecimalField(max_digits=8, decimal_places=3)
lat = models.DecimalField(max_digits=8, decimal_places=3)

So what should I be using?

Prometheus
  • 32,405
  • 54
  • 166
  • 302
  • I would use a FloatField. – Brandon Taylor Jun 08 '15 at 12:59
  • 7
    If you have a spatial backend, you could store those locations in a PointField, this would make spatial querying much easier. https://docs.djangoproject.com/en/1.8/ref/contrib/gis/model-api/#pointfield – yellowcap Jun 15 '15 at 11:41

3 Answers3

142

Float is generally an approximation, see here for some simple examples. You could get very nice results modifying your model to something like DecimalField(max_digits=9, decimal_places=6), since decimals are very important in coordinates but using more than 6 is basically meaningless.

Kye
  • 4,279
  • 3
  • 21
  • 49
mccc
  • 2,354
  • 1
  • 20
  • 22
  • This. And simply use enough decimal places to get whatever precision you need. Floating point numbers are good when you need to support a large range of order of magnitudes. You pay for that with sometimes surprising rounding, etc. behavior when combining multiple values together. – Christian Hudon Jun 08 '15 at 14:47
  • 19
    [See here for coordinates max length.](http://stackoverflow.com/questions/15965166/what-is-the-maximum-length-of-latitude-and-longitude) I would recommend `DecimalField(max_digits=9, decimal_places=6)` because "Each .000001 difference in coordinate decimal degree is approximately 10 cm in length." and I doubt you'll use more precision than that ;) – grokpot Sep 11 '15 at 16:41
42

Use PointField to store lat long

p = Point(85.3240, 27.7172,srid=4326)

Django: 1.X:

https://docs.djangoproject.com/en/1.11/ref/contrib/gis/model-api/#pointfield

Django: 2.X:

https://docs.djangoproject.com/en/2.2/ref/contrib/gis/model-api/#pointfield

Django: 3.X: https://docs.djangoproject.com/en/3.0/ref/contrib/gis/model-api/#pointfield

Amulya Acharya
  • 701
  • 14
  • 17
  • Is this available in MySQL DB ? – Hardik Gajjar Jun 20 '17 at 06:26
  • 2
    set django.contrib.gis.db.backends.mysql in your settings.DATABASE engine db config – Amulya Acharya Jun 20 '17 at 07:07
  • 2
    exactly what i wanted.. However the link does not contain any information on how to use the fields or what are the parameters used in them!? I'm a newbie to django so please let me know where I can find more information – pravin Mar 29 '18 at 10:10
  • 1
    https://docs.djangoproject.com/en/2.0/ref/contrib/gis/model-api/#pointfield for later versions of django. Using default django.contrib.gis model fields makes easy to give serialize data (e.g. Geojson serializer) and in Django forms Inputs. – Amulya Acharya Sep 20 '18 at 03:27
  • 4
    Note that you have to install the additional GDAL library on your system, otherwise you'll get this error: `django.core.exceptions.ImproperlyConfigured: Could not find the GDAL library`. – Babken Vardanyan Oct 30 '18 at 16:25
  • You also have to configure special database engine / connection for GIS. – Babken Vardanyan Nov 03 '18 at 07:25
  • https://docs.djangoproject.com/en/3.0/ref/contrib/gis/model-api/#pointfield – Amulya Acharya Jan 02 '20 at 03:16
  • 8
    This answer is not complete without a statement of the compatibility with vanilla django/databases. – Alper Mar 22 '20 at 16:47
  • 4
    PointField is nice, but it required postgis extension installed. This is no need if not process many data related to GIS. – dphans Aug 31 '20 at 10:53
  • @dphans yes, following my negative experience, I wouldn't recommend geodjango (django.contrib.gis) to just get a Pointfield due to its high complexity depending on all different external libraries – fmalina Sep 26 '21 at 09:55
8

The suggestion here to use DecimalField(max_digits=9, decimal_places=6) resulted in errors for me when trying to save locations from Google Maps.

If we assume that the most common use case is retrieving point locations from the Maps API, and a typical URL from Google Maps when right-clicking and selecting "What's Here?" yields something like:

https://www.google.com/maps/place/37°48'52.3"N+122°17'09.1"W/@37.814532,-122.2880467,17z

(random place)

So the longitude has 15 places before and after the decimal, which is why the accepted answer doesn't work. Since there's no reason to validate for "as short as possible" and db storage is cheap, I'm using:

    max_digits=22,
    decimal_places=16)
shacker
  • 14,712
  • 8
  • 89
  • 89
  • 8
    Thank you but I got a (-36.82931199999999, 174.71627980000001) so I use `DecimalField(max_digits=22, decimal_places=16, blank=True, null=True)` – C.K. Feb 11 '19 at 05:42
  • Ah! Thanks for that report - I'll update the answer. – shacker Feb 11 '19 at 18:25
  • 13
    As always, there's and XKCD for that https://xkcd.com/2170/ – mccc Jan 13 '21 at 17:07
  • @shacker In my case, if I use decimal_places=16 then it is appending Zeros in this number (38.8951) now it is like this (38.8951000000000000) and I don't want those extra zeros. But if I remove all the zeros from the last, then it is also removing that genuine zero (38.8950) and now (38.895) – Nikhil Bhardwaj Jul 13 '23 at 06:13