Display coordinates from a database on a Google Map from a backend made with the Django framework


Part II: www.jeffreyteruel.com/article/4

Complete Project: https://github.com/jteruel/checkin-map-django-googlemaps


Like the explorers of the past searching for some place they’ve never been to, we’re always trying to find something. To accomplish such tasks, chances are you’ve used apps such as Google Maps at some point to find out where to eat in an unfamiliar part of the city, or that office where your appointment or meeting will take place. It is also not uncommon to also see maps where the most recent earthquakes have occurred or the latest Tweets on Twitter. Throw in applications where you can track your most recent jogging trip around your neighborhood, you have a wide variety of apps which integrate some form of mapping with coordinates. From startups to business applications, integrating maps using coordinates can provide solutions to problems involving navigation and tracking locations. 

With a wide range of options and solutions we could make, any software engineer should be familiar with integrating map with a web or mobile application. We also need to be familiar with taking coordinates from a list of entries on a database to display on maps. As you can accomplish the task with any good web development framework, learning how to do it on one will help you to be able to do it on another. 

For this tutorial, the project we’ll be creating is a simple check-in app. It works similar to how you check in on any common mobile app. Every time you enter a new location on the text input, it will get the coordinates of the place and store it to the database. While Django’s default database is PostgreSQL, we’ll be using a MySQL database on MAMP. 

I’ve written this project to show an introduction for how this could be done using the Django framework, Angular, and Google Maps. It’s not meant for production, but it should give you an idea about the architecture and thought process to get you started on mapping coordinates on from a database. 

If you simply want to read and follow along, the complete files could be at Github:  https://github.com/jteruel/checkin-map-django-googlemaps

Prerequisites

For this project, we’ll be using the Python-based Django framework to build our main application. We’ll also be integrating Angular and Google Maps. The most recent versions of Angular require knowledge of Typescript, which I will not cover here. 

Django is based on the Python programming language, so you need to install that if you don’t already have it. To install packages, you will also need pip, which manages and allows you to install Python packages to your application. Also, you’ll need to install Virtualenv to ensure the project dependencies won’t affect any other current or future Python projects you may have on your computer. For Windows users, there are some slightly different commands you will need to learn, such as  mkvirtualenv [name of env] to create a virtual environment and running it with workon [name of env].

To integrate Google Maps to your application, will need an API-key from the Google Developer Console. You’ll need to login to the Developer Console, create an application, and add permissions to get a key for the Google Maps Javascript API. Once you get the key, save it somewhere you can find it. We’ll be using Angular Google Maps, which provide directives to display the coordinates and map. It’s no longer being maintained due to better options and the eventual phasing out of Angular 1. While it is obsolete, I will be using it as I find it simple to teach and integrate.

For our frontend, you should have some familiarity with the Bootstrap framework. If you want to follow along the tutorial looking at the entire code, the whole project can be found on my Github page here. 

Requirements

Our application’s workflow will be simple. A user (which could be yourself), can track checkin points on the map. An address can be entered on a form, which is then submitted to the server. That information will be geocoded, and you can get the latitude and longitude which can then be entered to the MySQL database. 

For our frontend, we’ll be using the Bootstrap framework 

The following Python packages will be needed: 

  • PyMySQL – To use a MySQL database with our application
  • Django REST Framework – To create a REST API for our map to display the coordinates
  • GeoPy – Take our input location and Geocode, giving us coordinates to enter into the database

Third Party CDNs: 


Set up Project

To get started, you can create a new folder on your desktop which you can use any name you want. This tutorial will use the name “checkin,” which we can make with mkdir checkin. Within your checkin folder, run the command to create a new Python development environment with virtualenv env. With that, you’ll be able to use pip to install all the necessary packages for your project, including Django. 

Now that you have your directory setup, you can now install Django with the command pip install django. Once that’s completed, you can then create a new project within the checkin directory using the command django-admin startproject [ your project name ]. We’ll call the app checkin map so it will look like  django-admin startproject checkinmap. After that, you can install some of the known Python packages we’ll need. To check that you’ve installed everything correctly, you can run python manage.py runserver which if set up correctly will give you a nice greeting.

For our database, you’ll need to turn on your MAMP or MySQL based database on your system. On your phpMyAdmin dashboard, create a new database and give it whatever name you want. For this example, we’ll call it “checkinmap” with the username and password set to “root.” Note that if you ever made the application in production, this would not be used as it would present a security risk.

Getting Started

Before we get into coding our app, we will need to make some adjustments to the current settings so our development will go more smoothly and save us time. We’ll be making some changes to our app settings.py in the checkinmap folder and manage.py on the root. The edits will allow us to use the MySQL database, create a static folder for our CSS/JS files, and to allow us to create and use our own html templates. 

For our packages, you can install them individually or together. Personally, my preference is to install them individually. Regardless of your approach, follow the command pip install [ package name ]. Install GeoPy, PyMySQL, and the Django Rest Framework. You can do so with the following command to get both at the same time: pip install djangorestframework geopy PyMySQL.

On the root folder of the application, will add the following lines after the first two lines of the app so MySQL can connect to our app's manage.py file:

 try:     import pymysql     pymysql.install_as_MySQLdb() except ImportError:     pass

Then we’ll change our database settings on the project settings.py file, including the username and password. Next, we adjust the settings to connect to our database and add a few lines at the end of our settings.py file. This would allow us to allow us to use a folder to use static files from a folder with our main images, CSS, and JS files. We'll also change the DIRS value in the Templates setting: 

#Templates settings

'DIRS': [os.path.join(BASE_DIR, 'templates')],

#Database settings

DATABASES = {     'default': {         'ENGINE': 'django.db.backends.mysql',         'NAME': 'checkinmap',         'USER': 'root',         'PASSWORD': 'root',         'HOST': '/Applications/MAMP/tmp/mysql/mysql.sock',         'PORT':'8889',     } }

#static files remain with app STATIC_URL = '/static/'   STATICFILES_DIRS = (     os.path.join(BASE_DIR, 'static'), ) STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

Now, you can create two new folders within our project folder for our static and templates. Then, to check that your database connection works you can run the following command: python manage.py migrate. This should migrate Django’s basic database configuration onto your new database on your phpMyAdmin dashboard. While this tutorial won’t cover or need admin access, you can create a superuser with the command: python manage.py createsuperuser. The command line will prompt you to create a username/password which you should keep if you decide to expand the app further to manage it from Django’s admin panel. The admin panel can be seen and accessed at localhost:8000/admin

We’ll be creating the workings of our app, and to prep for this we’ll make some additions to our urls.py on the checkinmap folder. The adjustments would allow us to eventually make a homepage and other work we’ll do later. It should now look like this: 

from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
    url(r'^record/', include('record.urls')),
]

 

It would also be a good time to create our base.html file in the templates folder, which will serve as the main guide for how our app will look like. Here, you can include your Bootstrap, styling, and jQuery files. Also, you can develop your header and footer and place them here. Later, any .html file will use what you work on here. 

Ensure that you include the line {% load static %} to ensure your CSS file or any static folder files such as a logo in that folder will be read. Your base.html should also include {{ form.media }} before the end of the head section for your form. Then, for our main page content we will include  {% block content %} and {% endblock content %} between the header and footer. Your base.html file should now look something similar as this:  

{% load static %} <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!--META TAGS--> <title>Check In Map</title>   <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> <!-- Bootstrap Core CSS --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" href="{% static 'css/general.css' %}"> {{ form.media }}   </head>   <body> <!-- Navigation --> <nav class="navbar navbar-default navbar-static-top" role="navigation">     <div class="navbar-header">         <button type="button" class="main-tog navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">             <span class="sr-only">Toggle navigation</span>             <span class="icon-bar"></span>             <span class="icon-bar"></span>             <span class="icon-bar"></span>         </button>         <a class="navbar-brand" href="/">           Checkin Map         </a>         </div>             <!--end navbar top-->       <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">       <ul class="nav navbar-nav navbar-left">         <li><a href="/">Home</a></li>         <li><a href="/record/create">Add A New Check-In</a></li>        </ul>  

   </div> </nav> <!--End Navigation--> <!--content--> {% block content %} {% endblock content %} <!--end content-->     <!--start footer--> <footer> <div class="container">   <div class="row">    <center> <p>Footer goes here</p></center>   </div> </div> </footer> </body> </html>


Creating the Application’s Map View

We’ve reached the part where we will work on the main workings of the app. Django requires us to make apps to accomplish this, so we’ll create a new app we’ll call record. We’ll run the command: python manage.py startapp record. Within the record folder, create the files named urls.py and forms.py. Before going forward, ensure that you have added the record app to the installed apps listing on your settings.py.

The first page we’ll create will be our homepage, which will have our map and a modal with our location entry form. Create a new file named home.html in our templates folder which we will include the lines in the exact order:  

{% extends 'base.html' %}

{% block content %} 

{% endblock %}

This would allow us to use what we created in our base.html (header and footer), so we don’t have to repeat our work. The section between {% block content %} and {% endblock %} is where we’ll place our html code for the homepage, including our Angular, and Google Maps configuration. We’ll first work on the first part of the page which will be the display of the coordinates from the database using Angular Google Maps. 

After we add in the necessary CDNs for Angular Google Maps to work, our Angular code within the page will allow us to get the data from the API we’ll be making, initiate the map with a center point, and get the coordinates for each point to display. The entire code should look something like the following: 

We initiated the Angular app using ng-app= “appMaps”, which we will refer to in the line angular.module('appMaps', ['uiGmapgoogle-maps']) within our script. We initiate the map with ng-controller="mainCtrl” where we define the center point and the main default settings of our map such as the zoom. Then, we define our markers starting with $scope.markers = []; , followed by an $http request and getting the data for each point. We define each marker’s latitude and longitude. Following Angular Google Map’s templating instructions, we include the markers and an individual info window for each point. 

Note that Django doesn’t work well with Angular’s code on templates as they both share the use of {{ }} for displaying data. To solve this, we renamed it to [ ] so we won’t have any conflicts or errors when retrieving data from the database. Also, we will set a height for our Angular Google Maps container otherwise we my just see a white screen. 

For our check-in creation form/modal, we have a button on the top of map <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addrecord">Open Modal</button>. Within the Bootstrap modal, we create a form with the method=POST, where all inputs will be both a location and textarea for any notes you’d like to add. To view the homepage, you add the line url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'), within the url patterns on the main urls.py file. Our home.html file within the  template folder should look something like this:

{% extends 'base.html' %} {% block content %} <div ng-app="appMaps" class="container">       <div id="map_canvas" ng-controller="mainCtrl" class="row">     <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB2Tph9faPbUfIvbGKWJia5BzgTFZxlZ4w"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.0.1/lodash.js" type="text/javascript"></script>   <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-simple-logger/0.1.7/angular-simple-logger.min.js"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-google-maps/2.4.1/angular-google-maps.min.js"></script>   <script type="text/javascript">       LocFac = "/record/api/";   angular.module('appMaps', ['uiGmapgoogle-maps'])     .config(function($interpolateProvider) {            $interpolateProvider.startSymbol('[');            $interpolateProvider.endSymbol(']');     })     .controller('mainCtrl', function($scope, $http, uiGmapGoogleMapApi, uiGmapIsReady) {         $scope.map = {           zoom: 3,           bounds: {},           center: { latitude: 18.46026, longitude: 170.50192 }         };         $scope.markers = [];               $http.get(LocFac).then(function(data) {           var markers = data.data;           angular.forEach(markers, function (marker) {                            marker.coords = {                 latitude: marker.latitude,                 longitude: marker.longitude              }            })           $scope.markers = markers;          });       });     </script>    <style>    .angular-google-map-container {        height: 500px;        width: auto;     }   </style>     <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addrecord">Open Modal</button>   <br/><br/>   <ui-gmap-google-map center="map.center" zoom="map.zoom" options="map.options">     <ui-gmap-marker ng-repeat="marker in markers" coords="marker.coords" options="marker.options" events="marker.events" idkey="marker.id">         <ui-gmap-window>            <div id="infowindow">               <h4>[ marker.location ]</h4>                 <h5>[ marker.text ]</h5>             </div>         </ui-gmap-window>     </ui-gmap-marker>   </ui-gmap-google-map>  </div> </div> <!--modal to add a new location--> <div id="addrecord" class="modal fade" role="dialog">   <div class="modal-dialog">     <!-- Modal content-->     <div class="modal-content">       <div class="modal-header">         <button type="button" class="close" data-dismiss="modal">&times;</button>         <h4 class="modal-title">New Record</h4>       </div>       <div class="modal-body">         <!--form to add a new record-->         <form action="/record/create/"  method="POST" enctype="multipart/form-data"> {% csrf_token %}          <label>Location</label>          <input name="location" id="location" class="form-control">          <label>Text</label>          <textarea name="text" id="text" class="form-control"></textarea>                          <br/>                    <input type="submit" value="Save" class="btn btn-md btn-primary">           </form>         <!--end form to add a new record-->       </div>       <div class="modal-footer">         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>       </div>     </div>   </div> </div> <!--end modal--> {% endblock %


We'll also create a folder in the templates named records to include a view to have a check-in creation form we can access. The records/create.html file should look something like this: 

{% extends "base.html" %} {% load static %} {% block content %} <div class="container">   <div class="row">       <div class="col-md-2"></div>       <div class="col-md-8">         <div class="panel panel-default">             <div class="panel-heading">Create Event</div>             <div class="panel-body">                  <form method="POST" enctype="multipart/form-data"> {% csrf_token %}                                     {{ form.as_p }}                  <br/>                                    <input type="submit" value="Save" class="btn btn-md btn-primary">                   </form>             </div>             </div>     </div>     </div> </div>   {% endblock content %}


The app is still unfinished. We have not made the data entry functions and the API where we get the data from. Part II will address this and we'll be closer to completing this application!



Contact Form