[GIS] Getting lat/lon from GeoDjango map/OSMWidget

geodjangoopenstreetmappointpython

I'm building a Django app in which I want users to be able to select a location by clicking on a map. That location is then stored in a Postgres database with the PostGIS extension.

Displaying the map in the form works fine, but the form's PointField that uses the OSMWidget does not return lat/lon values; when I print the return value I get something like SRID=4326;POINT (976253.7252582712 6477844.507319077)

How can I get the widget to return lat/lon values, or, alternatively, how can I convert these values before storing them in the database?

Some code snippets:

# forms.py

from django.contrib.gis import forms

class NewEntryForm(forms.Form):
   # ...
   location_name = forms.CharField(label='Name', max_length=20)
   location = forms.PointField(widget=forms.OSMWidget(
                  attrs={
                         'map_width': 600,
                         'map_height': 400,
                         'default_lat': 50.1091,
                         'default_lon': 8.6819,
                         'default_zoom': 9
                        }))

models.py

from django.contrib.gis.db import models

class Place(models.Model):
   name = models.CharField(max_length=20)
   coord = models.PointField(blank=True, null=True)

   def __str__(self):
      return self.name

views.py

from .models import Place
from .forms import NewEntryForm

def new_entry(request):
   if request.method == 'POST':
      form = NewEntryForm(request.POST)
      entries = request.POST
      if form.is_valid():
         new_place = Place(
                           name = request.POST['location_name'],
                           coord = request.POST['location']
                          )

         new_place.save()

Storing a point via the admin GUI works fine, but if I use the admin GUI to look at the locations stored via above form it's clear that things are not working correctly.

admin.py

from django.contrib.gis import admin
from .models import Place

@admin.register(Place)

class PlaceAdmin(admin.OSMGeoAdmin):
   pass

I'm using Django v. 3.0.5 with Python v. 3.6.10 on Ubuntu 16.04.

Best Answer

I noticed that the output of OSMWidget I posted in my question was actually printed after I had assigned it to the coordinates in my Place model. The actual widget output reads {"type":"Point","coordinates":[1011414.7582694523,6496495.14222066]}.

From this answer I gathered that the srid of the coordinates returned by the widget is 3857; my database uses 4326. What has solved my problem is writing an auxiliary function to reformat the widget output so that the coordinates will be automatically converted before the new Place object is saved.

# aux.py
from re import search

def format_pointstr_from_osmwidget(osm_output):
   srid = 3857

   pattern = '([0-9.]+,[0-9.]+)'

   c = search(pattern, osm_output).group(0).split(sep=',')

   coord = { 
            'srid': srid,
            'lat': c[0],
            'lon': c[1]
           }
   pointstr = "SRID={srid};POINT({lat} {lon})".format(**coord)

   return pointstr

In views.py I now reformat the widget output before creating a new Place object:

from .aux import format_pointstr_from_osmwidget

#...

def new_entry(request):
   if request.method == 'POST':
      form = NewEntryForm(request.POST)

   if form.is_valid():
         pointstr = format_pointstr_from_osmwidget(request.POST['location'])
         new_place = Place(
                           name = request.POST['location_name'],
                           coord = pointstr
                          )
         new_place.save()
Related Question