Search code examples
djangoleafletgispostgisgeodjango

Display Polygon in Leaflet Map from Geodjango Model


I'm developing a geospatial mapping application using geodjango and django-leaflet which lets users draw a polygon on a map and save that polygon to a model. I thought it would be simple to extract the saved polygon from the model and render it on a Leaflet map embedded in a template. However, I'm having considerable difficulty doing so. This is mostly due to me being a new web developer (I'm especially new to JS). Here's what I have so far:

models.py:

class newJob(BaseModel):
    job_name = models.CharField(max_length=64)
    job_desc = models.CharField(max_length=64)
    job_loc = models.PolygonField()
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)

The spatial data is saved successfully to the model using the form I have created (not shown). I have then created a simple function-based view to pull the required data from the database. I have created a 'raw' object (job_loc) and also serialized the data to geojson to create json_loc (as I'm not sure which is best to work with).

views.py:

def viewjob(request):

        req = request.GET

        job_name = newJob.objects.values_list('job_name', flat=True).get(pk=req['search'])
        job_desc = newJob.objects.values_list('job_desc', flat=True).get(pk=req['search'])
        job_loc = newJob.objects.values_list('job_loc', flat=True).get(pk=req['search'])

        json_loc = newJob.objects.filter(pk=req['search'])
        json_loc = serialize('geojson', json_loc, geometry_field='job_loc')
        context = {

        'job_name': job_name,
        'job_desc': job_desc,
        'job_loc': job_loc,
        'json_loc': json_loc

        }

        print(context)

        return render(request,'viewjob.html', context)

And the code in my template. I was hoping that I could pass job_loc or json_loc to leaflet and be done with it (given everything I'm working with is geospatial), but that's clearly not the case.


  {{ json_loc }}
 
  {{job_loc}}

  <script type="text/javascript">
      function map_init(map, options) {
          // zoom to point
          map.setView([51.9923, -2.1580], 12);

          // get polygon
          var polygon = "{{ json_loc }}";
          var polygon = L.polygon(polygon).addTo(map);
      }
  </script>


  {% leaflet_map "yourmap" callback="window.map_init_basic" %}

Here is a screenshot if I render the above code (might be helpful to see the data that's returned from json_loc and job_loc, respectively): enter image description here

I've heard that Ajax might be a potential solution here, but I'm unsure on how to implement this. I was expecting to load the data into the map directly without using an Ajax call (i.e. the polygon is passed from the view on page render, then inserted into the map directly).

Can anyone guide me on the best way to acomplish this?


Solution

  • It turns out the solution was very straightforward with the use of Django GeoJSON. Using Django GeoJSON, there's no need to mess around with serialising the polygon data in your view.

    Simply pass the raw spatial data from your database into views.py and then into your template like so:

    def index(request):
    
            req = request.GET
            job_loc = yourModel.objects.values_list('location', flat=True).get(pk=req['search'])
    
            context = {
                'job_loc': job_loc,
            }
    
            return render(request,'app/viewjob.html', context)
    

    And then in your template {% load geojson_tags %}:

      <script type="text/javascript">
        function map_init(map, options) {
          map.setView([51.9923, -0.5], 7);
          L.geoJson({{ job_loc|geojsonfeature|safe}}).addTo(map);
        }
    
      </script>