Build an Analytics Dashboard with Django and Arctype

Django's versatility makes it the ideal framework for developers endeavoring to collect website analytics, which can then be visualized and analyzed using Arctype's dashboard functionality—truly a perfect synergy.

4 months ago   •   12 min read

By Ochuko Onojakpor
Table of contents

Introduction

As Python's premier web framework, Django provides the foundation upon which many web applications have been built, facilitating rapid development without sacrificing stability.  Amongst other versatile functionalities, Django integrates seamlessly with SQL databases, so today, we'll be using the framework to implement basic site analytics data recording.  Then, we'll use this data to create gorgeous visualizations in an Arctype dashboard, which will keep track of the following:

  • Registrations, logins, and logouts
  • User activity by day
  • Breakdown of user activity on a selected day

To achieve this, we will be utilizing Django's ORM and Arctype (of course!)

Why Use Arctype for Site Analytics?

For this tutorial, we will be using Arctype to query our SQL data.  Running queries has become easier than ever with the assistance of Arctype's autocomplete and save functionalities.  You no longer have to remember every SQL command word-for-word—Arctype will complete them for you and allow you to save your commonly used queries for later.

We will also be building our analytics dashboard using the dashboard functionality.  Arctype dashboards allow you to seamlessly interact with your data, creating eye-catching visualizations with ease.  For more on Actype's functionalities, you can visit their official documentation.

Prerequisites for This Tutorial

To fully understand this tutorial, you should have the following:

  • Python 3.7 or newer
  • Arctype
  • A basic understanding of SQL
  • A basic understanding of Django
  • A text editor

With those prerequisites out of the way, we are ready to begin.

Getting Started with Django

Because simply writing a Django app to record website analytics could take up an entire post, in this tutorial, we will be cloning the Django application I have already built and subsequently connecting the application to an SQL server by editing the settings.py file.

Using Git to Clone the Django App

Run the code below in your command line to clone the repository containing the Django app on Github:

git clone https://github.com/Chukslord1/ARCTYPE_DJANGO_DASHBOARD.git

Editing Settings.py to Connect to Your SQL Server

In your settings.py file, edit the code below and replace it with the details required to connect to your SQL server:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'database_name',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'username',
        'PASSWORD': 'password',
    }
}
The fast and easy-to-use SQL client for developers and teams

Connecting Arctype to Your Database

While you've got your database information handy, let's go ahead and connect Arctype to your database.  After downloading Arctype and creating an account, you should be directed to an initial database setup page.  Assuming you already have a database, simply click "I have an existing database" and then select your database type:

Arctype database type selector

On the next screens, you'll need to enter your database credentials.  These should match the connection details in your settings.py.  If your database is running on localhost, you can simply use the values below:

arctype database connection

Finally, you have to create and name your workspace:

arctype workspace creation
Django will be unchained shortly.

With Arctype all ready to go, let's get our Django app set up to start filling this database with some user data!

Creating Django Models for Analytics Data

In your models.py file below, you will create seven models; Analytics,  Event, RegisterEvent, LoginEvent, ViewPageEvent, EditProfileEvent,  and LogoutEvent. Models are classes that define the way Django creates a table. The class name refers to a table name, and the class attributes refer to each table’s fields.

from django.db import models
import datetime

# Create your models here.
class Analytics(models.Model):
    name=name = models.TextField()
    stats= models.IntegerField(default=0)
    date= models.DateTimeField(default=datetime.datetime.now())

class Event(models.Model):
    name = models.TextField()
    username = models.TextField()
    ip = models.CharField(max_length=40)
    session = models.CharField(max_length=40)
    created = models.DateTimeField(default=datetime.datetime.now())

class RegisterEvent(models.Model):
    username = models.TextField()
    created = models.DateTimeField(default=datetime.datetime.now())

class LoginEvent(models.Model):
    username = models.TextField()
    created = models.DateTimeField(default=datetime.datetime.now())

class ViewPageEvent(models.Model):
    ip = models.CharField(max_length=40)
    session = models.CharField(max_length=40)
    created = models.DateTimeField(default=datetime.datetime.now())

class EditProfileEvent(models.Model):
    username = models.TextField()
    created = models.DateTimeField(default=datetime.datetime.now())

class LogoutEvent(models.Model):
    username = models.TextField()
    created = models.DateTimeField(default=datetime.datetime.now())

Here, the Event class defines the Event table to save the user’s actions on the site. The Analytics class defines the Analytics table to record the site’s analytics or numbers from the various events. As for the other model classes, we will utilize them later on in this tutorial to classify the events saved.

Building Dashboard Functionality with Django Views

The views.py file is where we will implement all the functionalities for your dashboard. Before diving into the fun part of the project, we're first going to go through each application view.

Importing the Required Django Libraries

At the very top, we need to initially import all of the Django libraries needed to create this application.  If you're trying to create your own analytics application from scratch, you should still start with these libraries.

from django.shortcuts import render,redirect
from django.contrib.auth.models import User, auth
from django.contrib import messages
from . models import Event,RegisterEvent,LoginEvent,ViewPageEvent,EditProfileEvent,LogoutEvent,Analytics
from django.contrib.sessions.models import Session
import datetime

Recording Registrations in the Register View

Now, let's tell our application how to both handle user registrations and record them:

def register(request):
    if request.method=="POST":
        username=request.POST.get("username")
        email=request.POST.get("email")
        password=request.POST.get("pwd")
        if User.objects.filter(email=email).exists() or User.objects.filter(username=username).exists():
            messages.add_message(request, messages.INFO,"user with email already exists", "danger")
            return render(request,"register.html")
        else:
            user = User.objects.create(username=username, password=password, email=email)
            user.set_password(user.password)
            user.save()
            register_user=Event(name="Registered",username=username,created=datetime.datetime.now())
            register_user.save()
            messages.add_message(request, messages.INFO,"Registration Succesful", "danger")
    return render(request,"register.html")

In the Python code above, we are collecting the email, username, and password passed in the POST request. We will then use the username to check if the user’s data already exists in the database. If the data exists, we will display an error message. Conversely, if the inputted username does not match any entry currently in the database, we will save the new user’s data, create an event for the registration, and pass a success message back to the user.  The register page should resemble the image below:

django dashboard application registration screen
Simple and (Not-So) Elegant

Handling Logins in a Django View

Now, as seen in the code below, we can implement the logic for the login system on this application:

def login(request):
    if request.method=="POST":
        email=request.POST.get("email")
        password=request.POST.get("pwd")
        username=User.objects.get(email=email).username
        user = auth.authenticate(username=username, password=password)
        if user is not None:
            auth.login(request, user)
            request.session["user"] = username
            login_user=Event(name="Logged In",username=request.session["user"],created=datetime.datetime.now())
            login_user.save()
            return redirect("App:index")
        else:
            messages.add_message(request, messages.INFO,"You have supplied invalid login credentials, please try again!", "danger")
            return render(request, 'login.html')
    return render(request,"login.html")

Here, we are collecting the email, username, and password passed in the POST request. We then use the username and password to authenticate the user. If the user’s data exists in the database, we redirect the user to the index page and record a login event. Otherwise, we show an error message.  Your login page should be like the one in the image below:

django dashboard login page
Our simple Django-powered login page.

Handling and Recording Logout Events with a Django View

We can now implement the logout system for our application using code that looks something like this:

def logout(request):
    logout_user=Event(name="Logged Out",username=request.session["user"],created=datetime.datetime.now())
    auth.logout(request)
    logout_user.save()
    messages.add_message(request, messages.INFO," you have been logged out", "danger")
    return redirect("App:login")

On a request to the logout view, we log the user out and display a logout message. Then, we redirect the user to the login page, while also creating an event for the logout action.

Creating the User Index View in Django

In this view, we are recording the page views for users’ pages (for each session) and allowing users to update their profile information. This is roughly what a rudimentary index view should look like:

def index(request):
    profile=request.user
    if not Event.objects.filter(session=request.session.session_key):
        view = Event(name="Viewed Page",ip=request.META['REMOTE_ADDR'],created=datetime.datetime.now(),session=request.session.session_key)
        view.save()
    if request.method=="POST":
        email=request.POST.get("email")
        username=request.POST.get("username")
        first_name=request.POST.get("first_name")
        last_name=request.POST.get("last_name")
        if email:
            profile.email=email
        if username:
            profile.username=username
        profile.first_name=first_name
        profile.last_name=last_name
        profile.save()
        edit=Event(name="Edited Profile",username=request.user,created=datetime.datetime.now())
        edit.save()
    context={"profile":profile}
    return render(request,"index.html",context)

In the Python code above, we are first checking if any data exists in the Event model that contains the same session key. If the query returns true, we will create an instance of the Event object with the session key and the current time.

Next, we are collecting the data needed to update the user’s profile—sent in a POST request—and then saving the data in the user’s profile whilst simultaneously recording an event for this edit action.

Finally, we are passing the user’s information to be rendered on the profile page in the context dictionary variable. The data points to be rendered are: the number of users, the number of page views, the number of active sessions, the number of inactive sessions, and the logout register.

Your  index dashboard should look like the one in the image below:

Django analytics app index dashboard
Home is where the index is

Using Arctype to Query for User Events

Now that we have begun to populate our new database tables, We can easily find data in your events table using the event’s name. To do this, simply click "Create a new query" and run the SQL SELECT statement below:

SELECT * FROM app_event WHERE name='Edited Profile';

This query should return results that look something like this:

Arctype django app event select query results
Our first three app events

How to Group User Events in Django

As more users register, login, and explore your site, your events table will ultimately contain thousands of rows—recording different types of events.  In order to more effectively run analytics on our data, we will need to group these events into separate tables.

#query to classify events into seperate tables
for i in Event.objects.all():
    if i.name == "Registered":
        if RegisterEvent.objects.filter(username=i.username,created=i.created):
            pass
        else:
            register=RegisterEvent(username=i.username,created=i.created)
            register.save()
    if i.name == "Logged In":
        if LoginEvent.objects.filter(username=i.username,created=i.created):
            pass
        else:
            login=LoginEvent(username=i.username,created=i.created)
            login.save()
    if i.name == "Viewed Page":
        if ViewPageEvent.objects.filter(ip=i.ip,session=i.session,created=i.created):
            pass
        else:
            page=ViewPageEvent(ip=i.ip,session=i.session,created=i.created)
            page.save()
    if i.name == "Edited Profile":
        if EditProfileEvent.objects.filter(username=i.username,created=i.created):
            pass
        else:
            edit=EditProfileEvent(username=i.username,created=i.created)
            edit.save()
    if i.name == "Logged Out":
        if LogoutEvent.objects.filter(username=i.username,created=i.created):
            pass
        else:
            logout=LogoutEvent(username=i.username,created=i.created)
            logout.save()

Here, we are running a loop through the events table and checking for the various event types before saving them into their respective model tables. However, before saving the data, we will check if the data already exists in the table.  This loop will run through all the rows in the events table.

Setting Up Analytics Using an Arctype Dashboard

Of course, Django is a versatile framework through which you could save some amount of useful analytical data into a separate table.  However, we can easily create more holistic and responsive analytics using an Arctype dashboard and a handful of queries.  As a note, for the purpose of this example dashboard, I have populated each of my analytics tables with a few thousand rows of sample (conforming) data.  

Creating and Saving Analytics Queries

Creating and saving queries in Arctype is as simple as clicking "Create a new query", entering your SQL code, naming the query, and clicking save.  Here's an example:

Arctype create new query workflow

In order to streamline dashboard creation for this guide, I will give you a few queries that are ready-to-use for your example dashboard.  You can always create your own (cooler) queries later, but for now, you should save these four queries:

Total Stats

--Return four columns with the total events from each user event table
SELECT 
(SELECT COUNT(*) FROM app_loginevent) AS 'logins',
(SELECT COUNT(*) FROM app_logoutevent) AS 'logouts',
(SELECT COUNT(*) FROM app_registerevent) AS 'registrations',
(SELECT COUNT(*) FROM app_viewpageevent) AS 'pageviews';

Pageviews by Day

--Return the total profile page views from every day with user activity, output formatted dates
SELECT
  DATE_FORMAT(created, '%M %e, %Y') as 'Date',
  COUNT(*) AS 'Pageviews'
FROM app_viewpageevent
GROUP BY Date;

User Events by Day

--Return total user events of each type for days when any event is recorded.
SELECT 
  DATE_FORMAT(dates.uf_date, '%M %e, %Y') as 'Date', 
  (SELECT
    COUNT(*) FROM app_registerevent
    WHERE DATE(app_registerevent.created) = dates.uf_date
   ) AS 'Registrations', 
  (SELECT
    COUNT(*) FROM app_loginevent
    WHERE DATE(app_loginevent.created) = dates.uf_date
   ) AS 'Logins', 
  (SELECT
    COUNT(*) FROM app_logoutevent
    WHERE DATE(app_logoutevent.created) = dates.uf_date
   ) AS 'Logouts'
FROM
  ((SELECT DATE(created) AS uf_date FROM app_registerevent)
  UNION
  (SELECT DATE(created) AS uf_date FROM app_loginevent)
  UNION
  (SELECT DATE(created) AS uf_date FROM app_logoutevent)) as dates
ORDER BY dates.uf_date;

Event Breakdown on Day

--Return total events of all types on dynamically linked date
SELECT
  'Registrations' AS 'Event',
  COUNT(*) AS 'Count'
  FROM app_registerevent
  WHERE DATE_FORMAT(app_registerevent.created, '%M %e, %Y') = {{input_date}}
UNION ALL
SELECT
  'Logins' AS 'Event',
  COUNT(*) AS 'Count' 
  FROM app_loginevent
  WHERE DATE_FORMAT(app_loginevent.created, '%M %e, %Y') = {{input_date}}
UNION ALL
SELECT
  'Logouts' AS 'Event',
  COUNT(*) AS 'Count' 
  FROM app_logoutevent
  WHERE DATE_FORMAT(app_logoutevent.created, '%M %e, %Y') = {{input_date}};

Now that we have our queries ready to go, let's start building our dashboard!

Creating a Dashboard for Your Database

To create an Arctype dashboard, simply click "Create a new dashboard".  You will be presented with a blank canvas—this is where the fun begins.

We'll start by creating scorecard-style totals for each type of user event.  This can be accomplished by simply dragging the "chart" box from the sidebar out into the dashboard canvas.  After the chart has been created, point it towards our Total Stats query, select "Scorecard" from "Chart type" and one of the four user event columns into the "Display Text" box like this:

Arctype dashboard create scorecard chart

For this dashboard, we'll make four of these scorecards to display each user event type.  After making all the scorecards, we can spruce things up by adding some header text:

arctype dashboard add header text

Adding Charts to an Arctype Dashboard

Next, let's create an area chart that displays user profile page views over time.  To do this, drag out another chart, select our Pageviews by Day query, select the area chart option from "Chart Type", and drag one column to each axis.  You'll want the date to display on the x-axis for this chart:

Arctype dashboard area chart creation

Let's do one more chart to display all user events over time using either a bar chart or stacked bar chart:

Arctype dashboard create bar chart

The stacked bar chart also achieves an incredible effect:

Arctype stacked barchart

Creating a Chart with Dynamically-Linked Values in a Dashboard

Finally, let's use dynamically-linked values to create a doughnut chart that changes based upon a table selection.  To do this, we'll first create a table using the same query as our bar chart (User Events by Day) :

Arctype dashboard create table

Because we don't need every column of this table to display, we can also clean things up using options in the "Advanced" tab on the right sidebar.

As you can see, each row in the table is selectable.  This is where the {{input_date}} dynamic value from our query will come in handy.  First, we will create a new chart element getting data from Event Breakdown on Day.  Then, in the "input_date" field, we can select a link to selectedRow.date, which will automatically update the date queried for our doughnut chart results whenever a new date in the table is selected.  

linked doughnut chart arctype analytics dashboard

After a bit of sprucing up, your dashboard will look something like this:

Endless possibilities exist with Arctype dashboards

Conclusion

Django's versatility makes it the ideal framework for developers endeavoring to collect website analytics, which can then be visualized and analyzed using Arctype's dashboard functionality—truly a perfect synergy.

Spread the word

Keep reading