Last active
January 22, 2024 15:18
-
-
Save hakib/ec462baef03a6146654e4c095142b5eb to your computer and use it in GitHub Desktop.
Revisions
-
hakib revised this gist
Sep 14, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ # https://hakibenita.com/how-to-turn-django-admin-into-a-lightweight-dashboard from django.contrib import admin from django.db.models import Count, Sum, Min, Max, DateTimeField from django.db.models.functions import Trunc from . import models -
hakib created this gist
Dec 23, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,106 @@ # https://hakibenita.com/how-to-turn-django-admin-into-a-lightweight-dashboard from django.contrib import admin from django.db.models import Count, Sum, Min, Max, DateTimeField) from django.db.models.functions import Trunc from . import models def get_next_in_date_hierarchy(request, date_hierarchy): if date_hierarchy + '__day' in request.GET: return 'hour' if date_hierarchy + '__month' in request.GET: return 'day' if date_hierarchy + '__year' in request.GET: return 'week' return 'month' @admin.register(models.SaleSummary) class LoadContractSummaryAdmin(admin.ModelAdmin): change_list_template = 'admin/dashboard/sales_change_list.html' actions = None date_hierarchy = 'created' # Prevent additional queries for pagination. show_full_result_count = False list_filter = ( 'device', ) def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False def has_change_permission(self, request, obj=None): return True def has_module_permission(self, request): return True def changelist_view(self, request, extra_context=None): response = super().changelist_view(request, extra_context=extra_context) # self.get_queryset would return the base queryset. ChangeList # apply the filters from the request so this is the only way to # get the filtered queryset. try: qs = response.context_data['cl'].queryset except (AttributeError, KeyError): # See issue #172. # When an invalid filter is used django will redirect. In this # case the response is an http redirect response and so it has # no context_data. return response # List view metrics = { 'total': Count('id'), 'total_sales': Sum('price'), } response.context_data['summary'] = list( qs .values('sale__category__name') .annotate(**metrics) .order_by('-total_sales') ) # List view summary response.context_data['summary_total'] = dict(qs.aggregate(**metrics)) # Chart period = get_next_in_date_hierarchy(request, self.date_hierarchy) response.context_data['period'] = period summary_over_time = qs.annotate( period=Trunc('created', 'day', output_field=DateTimeField()), ).values('period') .annotate(total=Sum('price')) .order_by('period') summary_range = summary_over_time.aggregate( low=Min('total'), high=Max('total'), ) high = summary_range.get('high', 0) low = summary_range.get('low', 0) response.context_data['summary_over_time'] = [{ 'period': x['period'], 'total': x['total'] or 0, 'pct': \ ((x['total'] or 0) - low) / (high - low) * 100 if high > low else 0, } for x in summary_over_time] return response This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,9 @@ # https://hakibenita.com/how-to-turn-django-admin-into-a-lightweight-dashboard from app.models import Sale class SaleSummary(Sale): class Meta: proxy = True verbose_name = 'Sale Summary' verbose_name_plural = 'Sales Summary' This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,118 @@ {% extends "admin/change_list.html" %} {% load i18n %} {% load humanize %} {% load mathtags %} {% load tz %} {% block content_title %} <h1> {% trans 'Sales Summary' %} </h1> {% endblock %} {% block result_list %} <div class="results"> <table> <thead> <tr> <th> <div class="text"> <a href="#">Category </a> </div> </th> <th> <div class="text"> <a href="#">Total </a> </div> </th> <th> <div class="text"> <a href="#">Total Sales </a> </div> </th> <th> <div class="text"> <a href="#"><strong>% Of Total Sales</strong></a> </div> </th> </tr> </thead> <tbody> {% for row in summary %} <tr class="{% cycle 'row1' 'row2' %}"> <td> {{ row.category }} </td> <td> {{ row.total }} </td> <td> {{ row.total_sales | default:0 }} </td> <td><strong> {{ row.total_sales | default:0 | percentof:summary_total.total_sales }} </strong> </td> </tr> {% endfor %} <tr style="font-weight:bold; border-top:2px solid #DDDDDD;"> <td> Total </td> <td> {{ summary_total.total | intcomma }} </td> <td> {{ summary_total.total_sales | default:0 }} </td> <td> 100% </td> </tr> </tbody> </table> </div> <h2> {% blocktrans %} Sales time (by {{ period}}) {% endblocktrans %} </h2> <style> .bar-chart { height: 160px; padding-top: 60px; display: flex; justify-content: space-around; overflow: hidden; } .bar-chart .bar { background-color: #79aec8; flex: 100%; align-self: flex-end; margin-right: 2px; position: relative; } .bar-chart .bar:last-child { margin: 0; } .bar-chart .bar:hover { background-color: #417690; } .bar-chart .bar .bar-tooltip { user-select: none; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; position: relative; z-index: 999; } .bar-chart .bar .bar-tooltip { position: absolute; top: -60px; left: 50%; transform: translateX(-50%); text-align: center; font-weight: bold; opacity: 0; } .bar-chart .bar:first-child .bar-tooltip { transform: initial; text-align: initial; left: 0; } .bar-chart .bar:last-child .bar-tooltip { transform: initial; text-align: right; right: 0; left: initial; } .bar-chart .bar:hover .bar-tooltip { opacity: 1; } </style> {% timezone 'UTC' %} <div class="results"> <div class="bar-chart"> {% for x in summary_over_time %} <div class="bar" style="height:{{x.pct}}%"> <div class="bar-tooltip"> {{x.total }}<br> {{x.period | date:"d/m/Y H:i"}} </div> </div> {% endfor %} </div> </div> {% endtimezone %} {% endblock %} {% block pagination %}{% endblock %}