Build Different

Adding TomTom Maps to a Django App: Building a Front End with a Map

Ryan Peden
Jul 20, 2021 • Last edit on Sep 20, 20226 min read

In part one of this series, we created a Django project, added a store locator app and a database model for storing locations. We have even filled our database with store locations. Now it’s time to add a TomTom map to our locator app.

Setting Up Django URLs

First, we must configure Django to assign a URL to the locator app. In the tomtom_django sub-folder, open urls.py and edit its contents to:

1from django.contrib import admin
2from django.urls import include, path
3
4urlpatterns = [
5 path('locator/', include('locator.urls')),
6 path('admin/', admin.site.urls),
7]
8Then, in the locator sub-folder, create a urls.py file and enter the following:
9from django.urls import path
10
11from . import views
12
13urlpatterns = [
14 path('', views.index, name='index'),
15]

With these two changes, we’ve told Django that the /locator URL should direct requests to the locator app and the index view that we’re about to create.

Creating Views

Next, in the locator sub-folder, open views.py and add:

1from django.shortcuts import render
2import json
3
4from .models import Location
5
6def index(request):
7 location_list = list(Location.objects.order_by('name').values())
8 location_json = json.dumps(location_list)
9 context = {'locations': location_json}
10 return render(request, 'locator/index.html', context)

This creates a view named index. It loads the list of stores from the database, converts them to JSON, and adds them to a context object so we’ll be able to use them when we render the index view template, we create next.

Inside the locator app folder, create a templates folder, and then inside the templates folder, create a locator folder. The folder hierarchy from the top level of the project should look like:

1│ tomtom_django/
2├── locator/
3 ├── templates/
4 ├── locator/

It might seem strange that we have another locator folder inside the templates, but we need it because of the way Django searches for templates. For example, if another Django app installed in our project has a template name (index.html) the same as one of the locator app’s templates, Django won’t know which one to load and throws an exception. The final locator sub-folder stops this from happening.

Now, create two files inside of the templates/locator called base.html and index.html. You can copy the contents of base.html from the GitHub repository. It contains boilerplate code to create our HTML page and add a title bar. The code that does all the hard work lives in index.html:

1{% extends "locator/base.html" %}
2{% block content %}
3 <style>
4 #map {
5 height: 500px;
6 width: 100%;
7 }
8
9 .mapboxgl-marker {
10 cursor: pointer;
11 }
12
13 .locator-popup {
14 font-size: 14px;
15 }
16 </style>
17 <h1>Store Locations</h1>
18 <h5>Click a location to see store details</h5>
19 <div id='map' class='map'></div>
20
21 <!-- load TomTom Maps Web SDK from CDN -->
22 <link rel='stylesheet' type='text/css' href='https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.13.0/maps/maps.css'/>
23 <script src='https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.13.0/maps/maps-web.min.js'></script>
24
25 <script>
26 // create the map
27 tt.setProductInfo('TomTom Maps Django Demo', '1.0');
28 let map = tt.map({
29 key: 'YOUR API KEY GOES HERE',
30 container: 'map'
31 });
32
33 // add store markers
34 let bounds = []
35 let storeLocations = JSON.parse("{{ locations|escapejs }}");
36
37 for (let storeLocation of storeLocations) {
38 let coordinates = [storeLocation.longitude, storeLocation.latitude];
39 bounds.push(coordinates);
40
41 // create popup to display store information when the marker is clicked
42 let popup = new tt.Popup().setHTML(`
43 <div class="locator-popup">
44 <h6>Store Name</h6>
45 <p>${storeLocation.name}</p>
46 <h6>Address</h6>
47 <p>${storeLocation.address}</p>
48 </div>
49 `);
50
51 let marker = new tt.Marker()
52 .setLngLat(coordinates)
53 .setPopup(popup)
54 .addTo(map);
55 }
56
57 // zoom the map to fit all markers
58 map.on('load', () => {
59 map.fitBounds(bounds, {
60 padding: { top: 50, bottom:50, left: 50, right: 50 }
61 });
62 })
63 </script>
64{% endblock %}

Understanding Our Mapping Code

Let’s go through the code one step at a time. We start by importing the base template to add a nice-looking title bar to our page. We then add a basic stylesheet that adds styles for our map container, maps markers (which we’ll use to represent store locations), and the popup displayed when you click on a store.

Next, add a couple of headers, add a div that will hold our map, and then add link and script elements to load the TomTom Maps Web SDK from TomTom’s CDN. If we were using the SDK with a framework like React, we should install it from NPM. But, if it’s being embedded in a web page (like this tutorial is), it’s best to load it from the CDN.

Finally, we have a script block containing all the code needed to make our map work. In a few lines of code, we can add a map to our page:

1tt.setProductInfo('TomTom Maps Django Demo', '1.0');
2let map = tt.map({
3key: ‘YOUR API KEY GOES HERE’,
4container: ‘map’
5});

Edit the key property to insert our API key from the TomTom developer portal. If you don’t have an API key yet, it only takes a minute to register and get one.

Next, we add markers to the map. Each marker will show up as an icon representing the store location:

1let bounds = []
2let storeLocations = JSON.parse("{{ locations|escapejs }}");
3
4for (let storeLocation of storeLocations) {
5let coordinates = [storeLocation.longitude, storeLocation.latitude];
6bounds.push(coordinates);
7
8// create popup to display store information when the marker is clicked
9let popup = new tt.Popup().setHTML(`
10 <div class="locator-popup">
11 <h6>Store Name</h6>
12 <p>${storeLocation.name}</p>
13 <h6>Address</h6>
14 <p>${storeLocation.address}</p>
15 </div>
16`);
17
18 let marker = new tt.Marker()
19 .setLngLat(coordinates)
20 .setPopup(popup)
21 .addTo(map);
22}

We start with a bounds array that will store the longitude and latitude coordinates of each marker. We’ll need this later to set the map’s zoom and center features automatically. Then, we parse the JSON store locations we passed into the template from Django.

Next, we loop through each store location. We’ll create an array from its coordinates with longitude first and latitude second since this is the format in which the TomTom market expects to receive the marker location. We then add it to the bounds array.

We then create a simple HTML popup that appears when the user clicks on the marker for this store. It shows the store location’s name and address.

Finally, we add the marker to the map. There's just one final step:

1map.on('load', () => {
2map.fitBounds(bounds, {
3 padding: { top: 50, bottom:50, left: 50, right: 50 }
4 });
5})

This code adds a function that’s called when the map finishes loading. It automatically zooms and re-centers the map to display all the store markers we just added. Now, we add a bit of padding to ensure the map does not cut off any markers.

Here’s how it looks in action:

image5

And if we click one of the store markers, we’ll see its information:

image4

And we’re done! We’ve created our very own Django store locator app.

Next Steps

If we’d like to go a step further, there are a couple of next steps to try. We could start by adding more information about each store — perhaps hours, phone number, and e-mail address. To do this, we can edit the Location model, add the fields, and then create and run a migration.

We may also consider adding a page that automatically retrieves the longitude and latitude of an address from the TomTom Search API’s Geocode service. This way, users can easily add new stores without needing to look up and enter the coordinates themselves.

If you haven’t started yet, why wait? Sign up for a TomTom developer account and create your excellent mapping app!

Get the developer
newsletter.

No marketing fuff. Tech content only.
Thanks for contacting us

We will reach out to you soon.
Blog cards
tomtom tech news