Skip to content

Commit b4d929a

Browse files
committed
almost finished with a couple of new blog posts
1 parent 0652da8 commit b4d929a

20 files changed

+446
-1
lines changed
Lines changed: 369 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
title: How to Add Maps to Django Web App Projects with Mapbox
2+
slug: maps-django-web-applications-projects-mapbox
3+
meta: Learn how to add maps and location-based data to your web applications using Mapbox.
4+
category: post
5+
date: 2018-05-19
6+
modified: 2018-05-21
7+
newsletter: False
8+
headerimage: /img/180519-django-maps/header.jpg
9+
headeralt: Python, Django and Mapbox logos are copyright their respective owners.
10+
11+
12+
Building interactive maps into a [Django](/django.html) web application
13+
can seem daunting if you do not know where to begin, but it is easier
14+
than you think if you use a developer tool such as
15+
[Mapbox](https://www.mapbox.com/).
16+
17+
<div id='map' width="100%" style='height:280px;margin-bottom:16px' class="shot rnd outl"></div>
18+
<script>
19+
mapboxgl.accessToken = 'pk.eyJ1IjoibWF0dG1ha2FpIiwiYSI6ImNqZzU0OXNtYjIzdmIyeHA5OG1sNnhid2YifQ.kzJityumPUk9f9i1vkmWAg';
20+
var map = new mapboxgl.Map({
21+
container: 'map',
22+
style: 'mapbox://styles/mapbox/streets-v10',
23+
center: [-77.03, 38.91],
24+
zoom: 9
25+
});
26+
</script>
27+
28+
In this post we will build a simple Django project with a single app
29+
and add an interactive map like the one you see above to the webpage that
30+
Django renders with the [Mapbox Maps](https://www.mapbox.com/maps/)
31+
[API](/application-programming-interfaces.html).
32+
33+
34+
## Our Tools
35+
[Python 3](/python-2-or-3.html) is strongly recommended for this tutorial
36+
because Python 2 will no longer be supported starting January 1, 2020.
37+
[Python 3.6.5](https://www.python.org/downloads/release/python-365/) to
38+
was used to build this tutorial. We will also use the following
39+
[application dependencies](/application-dependencies.html) to build
40+
our application:
41+
42+
* [Django](/django.html) web framework,
43+
[version 2.0.5](https://docs.djangoproject.com/en/2.0/)
44+
* [pip](https://pip.pypa.io/en/stable/) and
45+
[virtualenv](https://virtualenv.pypa.io/en/latest/), which come installed
46+
with Python 3, to install and isolate these Django and Rollbar libraries
47+
from your other applications
48+
* A [free Mapbox account](https://www.mapbox.com/) to interact with their
49+
[web API](/application-programming-interfaces.html) using
50+
[JavaScript](/javascript.html)
51+
52+
If you need help getting your
53+
[development environment](/development-environments.html) configured
54+
before running this code, take a look at
55+
[this guide for setting up Python 3 and Django on Ubuntu 16.04 LTS](/blog/python-3-django-gunicorn-ubuntu-1604-xenial-xerus.html).
56+
57+
This blog post's code is also available on GitHub within the
58+
[maps-django-mapbox directory of the blog-code-examples repository](https://github.com/fullstackpython/blog-code-examples).
59+
Take the code and use it for your own purposes because it is all
60+
provided under the MIT open source license.
61+
62+
63+
## Installing Dependencies
64+
Start the Django project by creating a new
65+
[virtual environment](/virtual-environments-virtualenvs-venvs.html)
66+
using the following command. I recommend using a separate directory
67+
such as `~/venvs/` (the tilde is a shortcut for your user's `home`
68+
directory) so that you always know where all your virtualenvs are
69+
located.
70+
71+
```bash
72+
python3 -m venv djangomaps
73+
```
74+
75+
Activate the virtualenv with the `activate` shell script:
76+
77+
```bash
78+
source djangomaps/bin/activate
79+
```
80+
81+
The command prompt will change after activating the virtualenv:
82+
83+
<img src="/img/180519-django-maps/virtualenv.jpg" width="100%" class="shot rnd outl" alt="Activate your djangomaps virtualenv.">
84+
85+
Remember that you have to activate your virtualenv in every new terminal
86+
window where you want to use dependencies in the virtualenv.
87+
88+
We can now install the [Django](https://pypi.python.org/pypi/Django/2.0.5)
89+
package into the activated but otherwise empty virtualenv.
90+
91+
```
92+
pip install django==2.0.5
93+
```
94+
95+
Look for the following output to confirm Django installed
96+
correctly from PyPI.
97+
98+
```
99+
Downloading https://files.pythonhosted.org/packages/23/91/2245462e57798e9251de87c88b2b8f996d10ddcb68206a8a020561ef7bd3/Django-2.0.5-py3-none-any.whl (7.1MB)
100+
100% |████████████████████████████████| 7.1MB 231kB/s
101+
Collecting pytz (from django==2.0.5)
102+
Using cached https://files.pythonhosted.org/packages/dc/83/15f7833b70d3e067ca91467ca245bae0f6fe56ddc7451aa0dc5606b120f2/pytz-2018.4-py2.py3-none-any.whl
103+
Installing collected packages: pytz, django
104+
Successfully installed django-2.0.5 pytz-2018.4
105+
```
106+
107+
The Django dependency is ready to go so now we can create our project
108+
and add some awesome maps to the application.
109+
110+
111+
## Building Our Django Project
112+
We can use the [Django](/django.html) `django-admin.py` tool to create
113+
the boilerplate code structure to get our project started.
114+
Change into the directory where you develop your applications. For
115+
example, I typically use `/Users/matt/devel/py/`. Then run the following
116+
command to start a Django project named `djmaps`:
117+
118+
```
119+
django-admin.py startproject djmaps
120+
```
121+
122+
The `django-admin.py` command will create a directory named `djmaps` along
123+
with several subdirectories that you should be familiar with if you have
124+
previously worked with Django.
125+
126+
Change directories into the new project.
127+
128+
```
129+
cd djmaps
130+
```
131+
132+
Create a new Django app within `djmaps`.
133+
134+
```
135+
python manage.py startapp maps
136+
```
137+
138+
Django will generate a new folder named `maps` for the project.
139+
We should update the URLs so the app is accessible before we write
140+
our `views.py` code.
141+
142+
Open `djmaps/djmaps/urls.py`. Add the highlighted lines so that URLs
143+
will check the `maps` app for appropriate URL matching.
144+
145+
```python
146+
""" (comments)
147+
"""
148+
~~from django.conf.urls import include
149+
from django.contrib import admin
150+
from django.urls import path
151+
152+
153+
urlpatterns = [
154+
~~ path('', include('maps.urls')),
155+
path('admin/', admin.site.urls),
156+
]
157+
```
158+
159+
Save `djmaps/djmaps/urls.py` and open `djmaps/djmaps/settings.py`.
160+
Add the `maps` app to `settings.py` by inserting the highlighted line:
161+
162+
```python
163+
# Application definition
164+
165+
INSTALLED_APPS = [
166+
'django.contrib.admin',
167+
'django.contrib.auth',
168+
'django.contrib.contenttypes',
169+
'django.contrib.sessions',
170+
'django.contrib.messages',
171+
'django.contrib.staticfiles',
172+
~~ 'maps',
173+
]
174+
```
175+
176+
Make sure you change the default `DEBUG` and `SECRET_KEY`
177+
values in `settings.py` before you deploy any code to production. Secure
178+
your app properly with the information from the Django
179+
[production deployment checklist](https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/)
180+
so that you do not add your project to the list of hacked applications
181+
on the web.
182+
183+
Save and close `settings.py`.
184+
185+
Next change into the `djmaps/maps` directory. Create a new file named
186+
`urls.py` to contain routes for the `maps` app.
187+
188+
Add these lines to the empty `djmaps/maps/urls.py` file.
189+
190+
```python
191+
from django.conf.urls import url
192+
from . import views
193+
194+
urlpatterns = [
195+
url(r'', views.default_map, name="default"),
196+
]
197+
```
198+
199+
Save `djmaps/maps/urls.py` and open `djmaps/maps/views.py` add the
200+
following two highlighted lines. You can keep the boilerplate comment or
201+
delete it.
202+
203+
```python
204+
from django.shortcuts import render
205+
206+
207+
~~def default_map(request):
208+
~~ return render(request, 'default.html', {})
209+
```
210+
211+
Next, create a directory for your template files named `templates` under
212+
the `djmaps/maps` app directory.
213+
214+
```
215+
mkdir templates
216+
```
217+
218+
Create a new file named `default.html` within `djmaps/maps/templates`
219+
that contains the following [Django template](/django-templates.html) markup.
220+
221+
```
222+
<!DOCTYPE html>
223+
<html>
224+
<head>
225+
<title>Interactive maps for Django web apps</title>
226+
</head>
227+
<body>
228+
<h1>Map time!</h1>
229+
</body>
230+
</html>
231+
```
232+
233+
We can test out this static page to make sure all of our code is
234+
correct, then we'll use Mapbox to embed a customizable map within
235+
the page. Change into the base directory of your Django project
236+
where the `manage.py` file is located. Execute the development
237+
server with the following command:
238+
239+
```bash
240+
python manage.py runserver
241+
```
242+
243+
The Django development server will start up with no issues other than an
244+
unapplied migrations warning.
245+
246+
```
247+
Performing system checks...
248+
249+
System check identified no issues (0 silenced).
250+
251+
You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
252+
Run 'python manage.py migrate' to apply them.
253+
254+
May 21, 2018 - 12:47:54
255+
Django version 2.0.5, using settings 'djmaps.settings'
256+
Starting development server at http://127.0.0.1:8000/
257+
Quit the server with CONTROL-C.
258+
```
259+
260+
Open a web browser and go to `localhost:8000`.
261+
262+
<img src="/img/180519-django-maps/map-time.png" width="100%" class="shot rnd outl" alt="Plain old HTML page.">
263+
264+
Our code works, but boy is that a plain-looking HTML page. Let's make the
265+
magic happen by adding JavaScript to the template to generate maps.
266+
267+
268+
## Adding Maps with Mapbox
269+
Head to [mapbox.com](https://www.mapbox.com/) in your web browser to
270+
access the Mapbox homepage.
271+
272+
<img src="/img/180519-django-maps/mapbox-homepage.jpg" width="100%" class="shot rnd outl" alt="Mapbox homepage.">
273+
274+
Click on "Get Started" or "Get Started for free" (the text depends on whether
275+
or not you already have a Mapbox account).
276+
277+
<img src="/img/180519-django-maps/sign-up.jpg" width="100%" class="shot rnd outl" alt="Sign up for a Mapbox account.">
278+
279+
Sign up for a new free developer account or sign in to your existing
280+
account.
281+
282+
<img src="/img/180519-django-maps/add-mapbox.png" width="100%" class="shot rnd outl" alt="Add Mapbox to your application.">
283+
284+
Click the "JS Web" option.
285+
286+
<img src="/img/180519-django-maps/method-installation.png" width="100%" class="shot rnd outl" alt="Choose the method of installation.">
287+
288+
Choose "Use the Mapbox CDN" for the installation method. The next two screens
289+
show some code that you should add to your `djmaps/maps/templates/default.html`
290+
template file. The code will look like the following but you will need to
291+
replace the `mapboxgl.accessToken` line with your own access token.
292+
293+
```
294+
<!DOCTYPE html>
295+
<html>
296+
<head>
297+
<title>Interactive maps for Django web apps</title>
298+
~~ <script src='https://api.mapbox.com/mapbox-gl-js/v0.44.2/mapbox-gl.js'></script>
299+
~~ <link href='https://api.mapbox.com/mapbox-gl-js/v0.44.2/mapbox-gl.css' rel='stylesheet' />
300+
</head>
301+
<body>
302+
<h1>Map time!</h1>
303+
~~ <div id='map' width="100%" style='height:400px'></div>
304+
~~ <script>
305+
~~ mapboxgl.accessToken = {{ mapbox_access_token }};
306+
~~ var map = new mapboxgl.Map({
307+
~~ container: 'map',
308+
~~ style: 'mapbox://styles/mapbox/streets-v10'
309+
~~ });
310+
~~ </script>
311+
</body>
312+
</html>
313+
```
314+
315+
Re-open `djmaps/maps/views.py` to update the parameters passed into the
316+
Django template.
317+
318+
```python
319+
from django.shortcuts import render
320+
321+
322+
def default_map(request):
323+
~~ # TODO: move this token to Django settings from an environment variable
324+
~~ # found in the Mapbox dashboard and getting started instructions
325+
~~ mapbox_access_token = 'pk.my_mapbox_access_token'
326+
~~ return render(request, 'default.html',
327+
~~ {'mapbox_access_token':mapbox_access_token})
328+
```
329+
330+
The Mapbox access token should really be stored in the Django settings
331+
file, so we left a TODO note to handle that as a future step.
332+
333+
Now we can try our webpage again. Refresh `localhost:8000` in your
334+
web browser.
335+
336+
<img src="/img/180519-django-maps/map-time-with-map.png" width="100%" class="shot rnd outl" alt="Screenshot of the Mapbox map showing up in our Django front end.">
337+
338+
Sweet, we've got a live, interactive map! It's kind of weird thought how it
339+
is zoomed out to view the entire world. Time to customize the map using
340+
a few JavaScript parameters.
341+
342+
343+
## Customizing the Map
344+
We can modify the map by changing parameters for the style, zoom level,
345+
location and many other attributes.
346+
347+
348+
349+
## What's Next?
350+
We just learned how to add interactive JavaScript-based maps to our
351+
[Django](/django.html) web applications, as well as modify the look
352+
and feel of the maps. Next try out some of the other APIs Mapbox
353+
provides including:
354+
355+
* [directions](https://www.mapbox.com/api-documentation/#directions)
356+
* [map matching](https://www.mapbox.com/api-documentation/#map-matching)
357+
* [geocoding](https://www.mapbox.com/api-documentation/#geocoding)
358+
359+
Questions? Let me know via
360+
[a GitHub issue ticket on the Full Stack Python repository](https://github.com/mattmakai/fullstackpython.com/issues),
361+
on Twitter
362+
[@fullstackpython](https://twitter.com/fullstackpython)
363+
or [@mattmakai](https://twitter.com/mattmakai).
364+
365+
Do you see a typo, syntax issue or wording that's confusing in this blog
366+
post? Fork
367+
[this page's source on GitHub](https://github.com/mattmakai/fullstackpython.com/blob/master/content/posts/180519-django-maps-mapbox.markdown)
368+
and submit a pull request with a fix or
369+
[file an issue ticket on GitHub](https://github.com/mattmakai/fullstackpython.com/issues).

0 commit comments

Comments
 (0)