Simple Bar Chart - Information is loaded from a Database Table
HELP

Above chart is loaded from STATS table.
To update the charts, please authenticate as admin, update the STATS table information and refresh the page.
Note: Admin account can be created using the createsuperuser command.


The Routing Settings

This page has a simple rule defined in the app/urls.py file:


# Contents of file: app/urls.py

urlpatterns = [
...
    # Charts from Input
    path('charts-input' , views.charts_input, name='charts-input' ),
...
]


Render Flow

The code that render this page use the information from STATS table.
The model comes with a inner method that selects all rows: get_report().
Once the STATS rows are selected, controller read the page template and inject the information.

Source: app/views.py - charts_input():


# Partial content from file: app/views.py
def charts_input(request):
    context = {'segment': 'charts_from_input'}
    html_template = loader.get_template('charts-from-input.html')

    stats, labels = Stats.get_report()
    data = [
        {
            'y': year,
            'a': '{:.2f}'.format( stats[year].get('prod1_sales') ), 
            'b': '{:.2f}'.format( stats[year].get('prod2_sales') ), 
            'c': '{:.2f}'.format( stats[year].get('prod3_sales') )  
        } for year in stats
    ]

    context['chart_data'] = json.dumps({
        'element': 'morris-bar-chart',
        'data': data,
        'xkey': 'y',
        'barSizeRatio': 0.70,
        'barGap': 3,
        'resize': True,
        'responsive': True,
        'ykeys': ['a', 'b', 'c'],  # it can be custom
        'labels': labels,
        'barColors': ['0-#1de9b6-#1dc4e9', '0-#899FD4-#A389D4', '#04a9f5']  # it can be custom
    })

    return HttpResponse(html_template.render(context, request))


Database Model - STATS

The model comes with a inner method that selects all rows: get_report().


class Stats(models.Model):
    
    year        = models.IntegerField(_('year')           , db_index=True)
    prod1_sales = models.IntegerField(_('product 1 sales'), db_index=True)
    prod2_sales = models.IntegerField(_('product 2 sales'), db_index=True)
    prod3_sales = models.IntegerField(_('product 3 sales'), db_index=True)

    class Meta:
        verbose_name = _('statistic')
        verbose_name_plural = _('stats')

    @classmethod
    def get_report(cls):

        data   = {}
        labels = ['prod1_sales', 'prod2_sales', 'prod3_sales']

        stats = Stats.objects.order_by('year').values()

        for line in stats:

            if line['year'] not in data:
                data[line['year']] = {}

            data[ line['year'] ]['prod1_sales'] = line['prod1_sales']
            data[ line['year'] ]['prod2_sales'] = line['prod2_sales']
            data[ line['year'] ]['prod3_sales'] = line['prod3_sales']

        return data, labels


HTML File

The chart data is rendered using Morris JS, a popular open-source chart library.
The source file core/templates/charts-from-input.html.