Abstract
A map in a website is the best way to make geographic data easily
accessible to users because it represents, in a simple way, the
information relating to a specific geographical area and is in fact
used by many online services.
Implementing a web map can be complex and many adopt the strategy of
using external services, but in most cases this strategy turns out to
be a major data and cost management problem.
In this talk we’ll see how to create a web map with the Python based
web framework Django using its GeoDjango module, storing geographic
data in your local database on which to run geospatial queries.
Through this intervention you can learn how to add a map on your
website, starting from a simple map based on Spatialite/SQLite up to a
more complex and interactive map based on PostGIS/PostgreSQL.
Transcript
This transcript was autogenerated. To make changes, submit a PR.
Hello everyone. I'm very happy to be here with you all, even if
remotely. In this talk, we see together how to build various
types of maps from sketch using Django. If you're asking yourself
what type of map we can build with Django, let's see an example
together right away. These maps show mountains, peaks and
spot elevation location. We all use maps like
this every day in web or mobile application. I built
this maps with Django using the free natural herd
geography map data set. In this talk we'll
see together how to build a maps like that. But first
I'll present myself. I'm Paolo Merci and I'm
the CTO of 20 tab, a photonic software
company based in Rome for which I work remotely. I'm a
software engineer and longtime python backend developer.
After using Django for a few years, I became a contributor to
the project. I also really like hiking in the mountains,
so I decided to build a map where I can put all
the points I've reached. I took this photo from the starting
point of my last hike. I was on the
italian Apenines and the sun has not yet
risen. But trust me, in the distance there is the
adriatic sea. The making of this map will
be a bit like this hike. We'll start from an easy
stretch with little slope and then we'll go up
in altitude where things will get more challenging.
But let's start from the basic about web maps a webmap
have many features. It can be static or dynamic.
You can interact with it, or you can only view it. The map
can use raster or vector tiles to represent the surface.
Usually the data is stored in a special database
and a webmap will use a Javascript library
to show data on your web pages.
On Wikipedia regarding webmaps, we can read that.
Webmap is the process of using the maps
delivered by geographic information system on the
Internet. But implementing a geographic information
system from scratch is beyond the scope of this talk.
To do this, as you can imagine, we are going to use Django,
my preferred web framework. The requirements to create
our map with Django are a stable and
supported version of Python and the latest stable version of
Django itself. In my example, I've installed
it in a virtual environment. To create the
mymap project. I switch to my project directory
and then users the start project Django command. The basic files
of our project will be created. After switching
to the MyMap directory, we create our markers
hub with a Django startup command. Again,
all the necessary file will be created for us.
Now we have CTO activate our markers application by
inserting its name in the list of installed apps
in the mymap settings file. At this point we can
proceed CTO insert in the markers views file a
new template view for the page of our map in the
markers template directory. We can now create a template
file for our map. For now we add only usual
boilerplate with a title but without a body content in
the marker's URL file. We must now add the path
to view our map using its template view. As the last
step, we include in turn the URL file
of the marker app in that of the project.
We just made a first view in Django, but it will show a
black page so we can avoid checking the browser content.
And let's move on with something more challenging. I took
this photo after an hour of working in the dark.
You can see the sunrise is in the distance. We are about
to start the high altitude path. As for our hike,
something will begin to been seen in our project as well. In fact,
we'll add a blank maps CTo our page using the leaflet library
leaflet is one of the most used JavaScript
libraries for webmaps. It's a free software and it is a desktop
and mobile friendly. Leaflet is very light, it weighs
less than 40, has a very good documentation
that you can read online. To use leaflet we need to link its
JavaScript and CSS module in our template.
We need also a Div tag with map hashid.
In addition, using the static template tag,
we also link our custom JavaScript and
cases file which we'll now create. We had
our CSS file in the static directory and inside
it we add only the basic rule to show a full
screen map in our JavaScript file. We add
the code to view our map using the defined variables.
We initiate an OpenStreet maps layer.
We hook the newly defined layer to our map.
The last statement users a map view that mostly contain the whole world
with the maximum zoom level possible. We can now
start our Django project with the run server command
and we can finally visit our map page. We just
created an empty map with Django. The result is pretty much what
you see now, a map without markers showing the world.
This photo shows the crossroad at the end of
the first part of my hike, just before a very challenging
uphill stretch design arisen for a
while and the landscape is clearly visible around.
Likewise, after having clearly visualized our map,
we'll now start with a bit more elaborate part,
writing more code to create our marker and display
them. It's time to get to know and activate
Geodjango. The Django Geographic module Django
added the geographic functionality a few years ago in the country
GIS module with specific fields,
multiple database backends, special queries and also admin
integration. Since then, many new useful features have
been added every year until the latest version. Before activating
it, we need to install some represents a mandatory
geodjango requirements is gdal.
It's an OS geo library for
reading and writing raster and vector geospatial data format.
It's released with a free software license and it has a variety
of useful command line for data translation
and processing. To easily install the
gdhel package on a Debian based system,
you can use the apt package manager. For other operating
system, you can read specific instructions in the Django documentation.
We can now activate Geodjango by adding
the contrib GIS module to the solid apps in
our project settings. To use Geodjango correctly,
we need to change our database engine and use one of the
compatible database backend. In this case, we have chosen to
use special SQLite. It's a special extension to SQL
SQLite, the Django default database backend.
It provides vector database functionality and
it's released with a free software license. It has a simple
architecture. A complete database is an ordinary
file as before on a debian based system.
We can install the specialite package using the apt
package manager. Let's add spatialite as
a database backend relating the default engine in our
project settings. We can now define
our marker model to store a location and
a name. Our two fields are both mandatory. The location
is a simple point field and we'll use the name to represent
the model. To easily insert new markers in the
map, we use the Django admin interface. We define
a marker admin class by inerting the Geodjango
admin class which use the OpenStreet maps layer
in its widget. We can now generate a new database migrations
and then apply it to our database.
We also create a new super user to access the
admin interface. After starting the project locally,
we can now start our project with the run server command
and we can visit our admin section.
Here is the page for inserting the markers in
our admin. As you can see, we have a text field
CTO enter the name and a widget that we can use to
manually navigate a map and then manually define our point
in the space. After having created more markers,
we can finally show them in our map. We can do that by
adding the information in our view. Here we are retrieving
all the markers from the database and converting them to Geojson
before adding them to the context of our view.
In our template, we use the JSON
script template tag to securely add our markers
to our page. The JSON script template tag
will generate a code like this.
Let's edit our JavaScript file and store the geojson
in a variable. Starting from this variable we build a
layer for our map and we extract also the
name of the single marker. Finally, we add
the layer in our map by setting the view to contains
all the data. We can now start our project with a
run server command and finally see our markers
in our map. In this map we see the few markers
I uploaded through the admin. They are inside the page
code, but the loading is still fluid and fast. You can
also see the pop up on the marker of the peak I'm
relating toward on this ike. But if we add a
lot more markers to show our maps, loading will be much slower
and leaflet will have a harder time rendering it.
We need a more complex solution.
This photo shows a beautiful landscape that came to
my side. At the end of that challenging climb, the IDS
peaks begin to be seen, but there is a still challenging passage
before reaching the summit. We then continue implementing the final version
of our map. First, let's start using PostGIs
as a new backend engine. Postgis is a PostgreSQL
extension and it's also the best database backend for Geodjango.
It internally integrates spatial data and
has spatialite type index and functions.
In order to use PostGIs as a database backend,
we need to install the Postgres C client library. As before,
you can do it easily with the APT package manager.
We modify the project database setting, adding the
PostGIs engine and the connection parameters
of our postgres database, which you may have locally
or remotely. Python requirements of our project
are increasing and therefore a good practice
is to create a requirements file with the package list.
We'll use Python Postgres database adapter,
Django Rest framework, its geographic addon, and also Django
filter. We install all the Python requirements
using the Python package installer module.
The packages that we'll use directly in the code of our
project are Django Rest framework and its geographic
add on, which we then insert in the list of
style adapts of our project settings.
Let's create a serializer for our marker class
in everything from rest framework JS serializer.
We only have to define the marker model,
the geographical field location, and also the optional
fields to be shown as additional properties.
Our intention is to expose our markers via our
RESTful API, and to do so we define a read only viewset.
We set the location as a field to filter our markers
and then a filter based on bound box.
We also return all our marker instances
without limitation or filters. In the
markers application, we define the URL of
our new endpoint using the Django REST framework default
router to create our path.
Finally, we add to the definition of the
URL of our project, a new path for the API that includes
the path just specified for our markers app.
After finishing our RESTful API,
we move on to update our JavaScript file. As we no
longer have the data preloaded on our page,
we no longer have a way to position the map so that it
contains all the markers we tried to locate the user.
In the positive case, we'll use its location to center the maps.
In the negative case, we locate him on an arbitrary
point in the map with a low zoom level by
no longer loading the marker directly on the page. We therefore
ask our endpoint to return only the markers of
the specific displayed area rest APIs
bank box string to build the marker layer, we ask our
endpoint for data asynchronously and extract the properties
we want to show in the popups. We invoke this flow every time
the users stop moving on the map. And finally
here is our complete map. In this example we can
see how the marker in a specific map area look relating
take place in a very fluid way because the number of cases
occur only when the movement on the map stops and therefore
the data traffic is reduced to the essential as well
as the rendering of the marker carried out by leaflet,
the hike has also reached its final destination.
Unfortunately the view is a bit covered, but we can finally add a
new marker on our map. It was one of the longest hike
I ever made and I hope to be able to do new one soon.
There are also many other features that can be added
in the future, for example markers customization and
popup to show more information marker filtering based on relation
data, the clustering of the marker but in the front end
to improve the visualization and backend to make the loading of data
more efficient, use of geocoding services to add
marker locations starting from the address and so on at the
end of the talk before saying goodbye, I want to share with you some
tips based on my experience as a map developer with Django.
The first one is read the documentation in the Django website.
It's full of information about Geodjango. Read also
the details about geographical queries in the post
JS website. It helps you to understand how
things work at a lower level. Read the source
code of Bot project in GitHub because there is
something you can learn only from the code and finally
search for questions on Stack exchange,
but try to answer them by yourself. Last but
not least, you can also study this presentation because
it is released with a Creative Commons license
in Twentytab, the company I work for. We have
developed many map with Django. You can find more about our open
source project and our patonic work using these contacts.
To find out more about my personal work with Python and
Django, use all my contacts using this QR code.
You can download this presentation from my website.
Thanks again for having me. Enjoy the tool in the conference.