Artigo original: How to create an analytics dashboard in a Django app

Olá, pessoal!

Python, visualização de dados e programação são os tópicos aos quais me dedico profundamente. É por isso que gostaria de compartilhar com você minhas ideias, bem como meu entusiasmo por descobrir novas maneiras de apresentar dados de maneira significativa.

O caso que vou abordar é bastante comum: você tem dados no back-end da sua aplicação e deseja dar forma a eles no front-end. Se essa situação parece familiar a você, este tutorial pode ser útil.

Depois de concluí-lo, você terá uma aplicação desenvolvida com Django, com tabelas e gráficos dinâmicos interativos.

Pré-requisitos

Para percorrer as etapas com confiança, você precisa de um conhecimento básico do framework Django e de um pouco de criatividade. ✨

Para acompanhá-lo, você pode baixar o exemplo do GitHub.

Aqui está uma breve lista das ferramentas que vamos usar:

Nota do tradutor: no momento desta tradução, o Python se encontra em sua versão 3.10.4. As soluções constantes aqui deverão funcionar, mesmo assim.

Se você já configurou um projeto no Django e se sente confiante sobre o fluxo básico de criação de aplicações, pode ir direto para a seção Conectando dados ao Flexmonster, que explica como adicionar componentes de visualização de dados a ele.

Vamos começar!

Começando com o Django


Antes de mais nada, vamos conferir se você já instalou o Django em sua máquina. A regra geral é instalá-lo em seu ambiente virtual configurado anteriormente –uma ferramenta poderosa para isolar seus projetos uns dos outros.

Além disso, verifique se você está ativo em um diretório recém-criado. Abra seu console e inicialize um projeto do Django com este comando:

django-admin startproject analytics_project

Agora, há um novo diretório chamado analytics_project. Vamos verificar se fizemos tudo certo. Vamos para analytics_project e iniciar o servidor com um comando de console:

python manage.py runserver

Abra http://127.0.0.1:8000/ no seu navegador. Se o que você vê na página é este foguete incrível, é sinal de que está tudo certo:

DjangoRocket

Em seguida, crie uma aplicação em seu projeto. Vamos chamá-lo de dashboard:

python manage.py startapp dashboard

Aqui vai uma dica: se você não tiver certeza sobre a diferença entre o conceito de apps e de projetos em Django, (texto em inglês), dedique um tempo a aprender sobre isso para ter uma visão clara de como os projetos do Django são organizados.

Lá vamos nós. Agora, vemos um novo diretório dentro do projeto. Ele contém os seguintes arquivos:

__init__.py – para fazer o Python tratá-lo como um pacote

admin.py – configurações para as páginas de administração do Django

apps.py – ajustes para as configurações da aplicação

models.py – classes que serão convertidas em tabelas de banco de dados pelo ORM do Django

tests.py – classes de teste

views.py – funções e classes que definem como os dados são exibidos nos templates

Depois, é necessário registrar a aplicação no projeto. Vá para analytics_project/settings.py e anexe o nome da aplicação à lista INSTALLED_APPS :

INSTALLED_APPS = [
	'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'dashboard',
]

Agora, nosso projeto está ciente da existência da aplicação.

Views


No dashboard/views.py, vamos criar uma função que direciona um usuário para os templates específicos definidos na pasta dashboard/templates. As visualizações (em inglês, views) também podem conter classes.

Veja como a definimos:

from django.http import JsonResponse
from django.shortcuts import render
from dashboard.models import Order
from django.core import serializers

def dashboard_with_pivot(request):
    return render(request, 'dashboard_with_pivot.html', {})

Uma vez chamada, esta função renderizará dashboard_with_pivot.html, um template que definiremos em breve. Ele conterá os componentes da tabela e dos gráficos dinâmicos.

Mais algumas palavras sobre esta função. Seu argumento request, uma instância de HttpRequestObject, contém informações sobre a solicitação – por exemplo, o método HTTP usado (GET ou POST). O método render procura por templates de HTML em um diretório de templates localizado dentro do diretório da aplicação.

Também precisamos criar um método auxiliar que envie a resposta com dados para a tabela dinâmica no front-end da aplicação. Vamos chamá-lo de pivot_data:

def pivot_data(request):
    dataset = Order.objects.all()
    data = serializers.serialize('json', dataset)
    return JsonResponse(data, safe=False)

Provavelmente, seu IDE estará informando que não pode encontrar a referência a Order em models.py. Sem problemas - trataremos disso mais tarde.

Templates

Por enquanto, vamos aproveitar o sistema de templates do Django.

Vamos criar um diretório templates dentro de dashboard e criar o primeiro template de HTML, chamado dashboard_with_pivot.html. Ele será exibido ao usuário mediante solicitação. Aqui, também adicionamos os scripts e contêineres para componentes de visualização de dados:

<head>
  <meta charset="UTF-8">
  <title>Dashboard with Flexmonster</title>
  <script src="https://cdn.flexmonster.com/flexmonster.js"></script>
  <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  <link rel="stylesheet" href="https://cdn.flexmonster.com/demo.css">
</head>
<body>
<div id="pivot-table-container" data-url="{% url 'pivot_data' %}"></div>
<div id="pivot-chart-container"></div>
</body>

Funções de visualização de mapeamento para URLs

Para chamar as visualizações e exibir templates de HTML renderizados para o usuário, precisamos mapear as visualizações para os URLs correspondentes.

Aqui tem uma dica: um dos princípios de design de URL do Django é sobre um acoplamento fraco, (texto em inglês). Não devemos fazer URLs com os mesmos nomes das funções do Python.

Vá para analytics_app/urls.py e adicione as configurações relevantes ao dashboard da aplicação em nível de projeto.

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('dashboard/', include('dashboard.urls')),
]

Agora, os URLs da aplicação de dashboard podem ser acessados, mas somente se forem prefixados com dashboard.

Depois, vá para dashboard/urls.py (crie este arquivo se ele não existir) e adicione uma lista de padrões de URL que são mapeados para as funções de visualização:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.dashboard_with_pivot, name='dashboard_with_pivot'),
    path('data', views.pivot_data, name='pivot_data'),
]

Modelos


Finalmente, chegamos à modelagem de dados. Essa é a minha parte favorita.

Como você deve saber, um modelo de dados é uma representação conceitual dos dados armazenados em um banco de dados.

Como o objetivo deste tutorial é mostrar como construir uma visualização interativa de dados dentro da aplicação, não vamos nos preocupar muito com a escolha do banco de dados. Usaremos o SQLite – um banco de dados leve que acompanha o servidor de desenvolvimento para a web do Django.

Lembre-se, porém, de que esse banco de dados não é a escolha apropriada para o desenvolvimento em produção. Com o ORM do Django, você pode usar outros bancos de dados que usam a linguagem SQL, como o PostgreSQL ou o MySQL.

Por uma questão de simplicidade, nosso modelo consistirá em uma classe. Você pode criar mais classes e definir relações entre elas, complexas ou simples.

Imagine que estamos projetando um painel para o departamento de vendas. Então, vamos criar uma classe Order (em português, o pedido) e definir seus atributos em dashboard/models.py:

from django.db import models


class Order(models.Model):
    product_category = models.CharField(max_length=20)
    payment_method = models.CharField(max_length=50)
    shipping_cost = models.CharField(max_length=50)
    unit_price = models.DecimalField(max_digits=5, decimal_places=2)

Trabalhando com um banco de dados


Agora, precisamos criar um banco de dados e preenchê-lo com registros.

Como, no entanto, podemos traduzir nossa classe modelo para uma tabela de banco de dados?

É aqui que o conceito de migração é útil. A migração é simplesmente um arquivo que descreve quais mudanças devem ser aplicadas ao banco de dados. Toda vez que precisamos criar um banco de dados baseado no modelo descrito pelas classes do Python, usamos a migração.

Os dados podem vir como objetos, dicionários ou listas do Python. Desta vez, vamos representar as entidades do banco de dados usando classes do Python que estão localizadas no diretório models.

Crie a migração para a aplicação com um comando:

python manage.py makemigrations dashboard

Aqui, especificamos que a aplicação deve dizer ao Django para aplicar migrações para os modelos da aplicação de dashboard.

Após criar um arquivo de migração, aplique as migrações descritas nele e crie um banco de dados:

python manage.py migrate dashboard

Caso perceba que há um novo arquivo db.sqlite3 no diretório do projeto, é sinal de que estamos prontos para trabalhar com o banco de dados.

Vamos criar instâncias da nossa classe Order. Para isso, usaremos o shell do Django - é semelhante ao shell do Python, mas permite acessar o banco de dados e criar entradas.

Então, inicie o shell do Django:

python manage.py shell

Escreva no console interativo do shell o seguinte código:

from dashboard.models import Order

>>> o1 = Order(
... product_category='Books',
... payment_method='Credit Card',
... shipping_cost=39,
... unit_price=59
... )
>>> o1.save()

Você pode criar e salvar quantos objetos precisar do mesmo modo.

Conectando dados ao Flexmonster


Aqui está o que eu prometi explicar.

Vamos descobrir como passar os dados do seu modelo para a ferramenta de visualização de dados no front-end.

Para fazer o back-end e o Flexmonster se comunicarem, podemos seguir duas abordagens diferentes:

  • Usar o ciclo de request-response. Podemos usar o Python e o mecanismo de template do Django para escrever código em JavaScript diretamente no template.
  • Usar uma solicitação assíncrona (AJAX) que retorna os dados em JSON.

Na minha opinião, o segundo é o mais conveniente por vários motivos. Em primeiro lugar, o Flexmonster entende JSON. Para ser mais precisa, ele pode aceitar uma matriz de objetos JSON como dados de entrada. Outro benefício do uso de solicitações assíncronas é a maior velocidade de carregamento da página e o código mais sustentável.

Vamos ver como isso funciona.

Vá para templates/dashboard_pivot.html.

Aqui, criamos dois contêineres div, onde a tabela e os gráficos dinâmicos serão renderizados.

Dentro da chamada de Ajax, fazemos uma requisição com base no URL contido na propriedade data-URL. Em seguida, informamos à solicitação Ajax que esperamos que um objeto JSON seja retornado (definido por dataType).

Depois que a solicitação for concluída, a resposta em JSON retornada pelo nosso servidor será definida para o parâmetro data e a tabela dinâmica, preenchida com esses dados, será renderizada.

O resultado da consulta (a instância de JSONResponse) retorna uma string que contém um objeto de array com metainformações adicionais. Então, devemos adicionar uma pequena função para processamento de dados no front-end. Ela extrairá apenas os objetos aninhados de que precisamos e os colocará em um único array. Isso ocorre porque o Flexmonster aceita apenas um array de objetos JSON sem níveis aninhados.

function processData(dataset) {
    var result = []
    dataset = JSON.parse(dataset);
    dataset.forEach(item => result.push(item.fields));
    return result;
}

Após o processamento dos dados, o componente os recebe no formato correto e realiza todo o trabalho árduo de visualização dos dados. Uma grande vantagem é que não há necessidade de agrupar ou agregar os valores dos objetos manualmente.

Veja a aparência do script completo no template:

function processData(dataset) {
    var result = []
    dataset = JSON.parse(dataset);
    dataset.forEach(item => result.push(item.fields));
    return result;
}
$.ajax({
    url: $("#pivot-table-container").attr("data-url"),
    dataType: 'json',
    success: function(data) {
        new Flexmonster({
            container: "#pivot-table-container",
            componentFolder: "https://cdn.flexmonster.com/",
            width: "100%",
            height: 430,
            toolbar: true,
            report: {
                dataSource: {
                    type: "json",
                    data: processData(data)
                },
                slice: {}
            }
        });
        new Flexmonster({
            container: "#pivot-chart-container",
            componentFolder: "https://cdn.flexmonster.com/",
            width: "100%",
            height: 430,
            //toolbar: true,
            report: {
                dataSource: {
                    type: "json",
                    data: processData(data)
                },
                slice: {},
                "options": {
                    "viewType": "charts",
                    "chart": {
                        "type": "pie"
                    }
                }
            }
        });
    }
});

Não se esqueça de incluir este código JavaScript em tags <script> .

Ufa! Estamos quase no final desta aplicação.

Personalização de campos

O Flexmonster fornece uma propriedade especial de fonte de dados que permite definir tipos de dados de campo, legendas personalizadas e definir hierarquias de vários níveis.

Esse é um bom recurso – podemos separar elegantemente os dados e sua apresentação diretamente na configuração do relatório.

Adicione-a à propriedade dataSource do relatório:

mapping: {
    "product_category": {
        "caption": "Product Category",
        "type": "string"
    },
    "payment_method": {
        "caption": "Payment Method",
        "type": "string"
    },
    "shipping_cost": {
        "caption": "Shipping Cost",
        "type": "number"
    },
    "unit_price": {
        "caption": "Unit Price",
        "type": "number"
    }
}

Projeto do painel


Para fazer o painel, renderizamos duas instâncias do Flexmonster (você pode criar quantas quiser, dependendo dos objetivos de visualização de dados que deseja alcançar). Uma das instâncias é para a tabela dinâmica com dados resumidos e a outra é para os gráficos dinâmicos.

Ambas compartilham da mesma fonte de dados do nosso modelo. Eu encorajo você a tentar fazê-los funcionar em sincronia: com o evento reportchange, você pode fazer uma instância reagir às mudanças de outra.

Você também pode redefinir a funcionalidade do botão 'Exportar' na Barra de Ferramentas para salvar seus relatórios no servidor.

Resultados

Vamos iniciar o servidor de desenvolvimento Django e abrir http://127.0.0.1:8000/dashboard/ para ver o painel resultante:

DjangoFlexmonster

Parece bom, não é?

Conclusão

Aqui, aprendemos como criar uma aplicação do Django simples e como exibir os dados no lado do client na forma de um painel de análise. Espero que tenham gostado do tutorial!

Referências

O código-fonte do tutorial pode ser encontrado no GitHub. Aqui, temos o projeto de integração do Flexmonster e do Django que me inspirou a fazer este tutorial.

Além disso, recomendo percorrer conceitos importantes na documentação para dominar o Django (textos da documentação em inglês):

Se este artigo foi útil para você, compartilhe-o! Obrigada!