Extending with Python

White Label Data is as a platform that allows you to rapidly create data applications without having to write code. That said, there may be instances when you want to extend White Label Data with custom Python code. Some examples of when this may be necessary are:

  • When you want to call a custom API to acquire data
  • When you want to create your own API to be consumed by your front-end code
  • When you want to create a custom data transformation

Creating Python Extensions

Hashpath will need to enable your instance to support extensions. Extensions are location in a folder called /extensions in your Git repostory. The backend of your White Label Data application is implemented using the Django Web Framework. You will be extending this framework. There are a number of special files in that folder:

urls.py

This is a Django urls file that contains any new URL patterns you wish to add to the routing.

from django.urls import re_path, path, include
from . import apis

urlpatterns = [
	path('api/mynewapi', apis.mynewapi)
] 

The above will add the URL to your app. If your app has a DNS name of “myapp.com”, the full URL will be https://myapp.com/api/mynewapi. You can then use this API from within your front-end pages using Javascript AJAX calls using the built-in Axios library. For more information on extending URLs, see the Django URL Dispatcher documentation.

apis.py

This Django Python file is used to add your Django view code that implements the APIs specified in your urls.py file.

from django.http import JsonResponse

def mynewapi(request):
	if not request.user.is_authenticated:
		return JsonResponse(status=403, data={'status':'error','message':"Forbidden"})

	if (request.method == 'GET'):
		# Process GET request
		return JsonResponse(response)
	elif (request.method == 'POST'):
		# Process POST request
		return JsonResponse(response)

	return JsonResponse(status=400, data={'status':'error','message':"Bad parameters"})

For more information on implementing JSON responses from Django views, see here.

pipeline.py

This is a White Label Data Python file for implementing custom queries and transformation. This is useful when you need to call into a custom API from within the White Label Data pipeline and map results to charts and other figures.

Custom Queries

To call a custom query, you add the following to your pipeline in a Layer file:

"steps" : [
    {
        "action" : "custom_query",
        "function_name" : "my_custom_query"
    }
]

And then create a Python function with that name. It takes filters as an argument. Filters is a Python dictionary containing all the name-value pair filters associated with the request. These include both page filters and user attributes from Auth0.

TIP: There is a special filter called wld_uid (accessed as filters['wld_uid']) that returns the current Auth0 user ID for the custom query.

import pandas as pd

def my_custom_query(filters):

    my_data = [
       [1, 'red'],
       [2, 'blue'],
       [3, 'red']
    ]

    columns = ['id', 'color']

    response = pd.DataFrame(my_data, columns=columns)
    return response

Custom Transforms

To call a custom transform, you add the following to your pipeline in a Layer file:

"steps" : [
    {
        "action" : "transform",
        "operation" : "custom",
        "function_name" : "my_custom_transform"
    }
]

And then create a Python function with that name. It takes the current DataFrame as an argument (called input_df below) and filters as an argument. Filters is a Python dictionary containing all the name-value pair filters associated with the request. These include both page filters and user attributes from Auth0. The purpose of your transform function is to read and modify the inputted DataFrame and return it so that it can continue in the pipeline process.

TIP: There is a special filter called wld_uid (accessed as filters['wld_uid']) that returns the current Auth0 user ID for the custom query.

import pandas as pd

def my_custom_transform(input_df, filters):

	newcol = [ 'a', 'b', 'c']
    input_df['col1'] = newcol

    return input_df