From aa31aefb4235c5678bfc299ce199c347f6829bd1 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 2 Oct 2024 12:13:05 +0200 Subject: [PATCH] Pagination for list of devices in dashboard and lots --- dashboard/mixins.py | 28 ++++++++++- dashboard/templates/unassigned_devices.html | 7 +++ dashboard/templatetags/__init__.py | 0 dashboard/templatetags/paginacion.py | 19 ++++++++ dashboard/templatetags/range.py | 23 ++++++++++ dashboard/views.py | 19 +++----- device/models.py | 51 ++++++++++++++++----- prevision.txt | 23 ---------- 8 files changed, 121 insertions(+), 49 deletions(-) create mode 100644 dashboard/templatetags/__init__.py create mode 100644 dashboard/templatetags/paginacion.py create mode 100644 dashboard/templatetags/range.py delete mode 100644 prevision.txt diff --git a/dashboard/mixins.py b/dashboard/mixins.py index c28dcf8..3ebac58 100644 --- a/dashboard/mixins.py +++ b/dashboard/mixins.py @@ -1,5 +1,5 @@ from django.urls import resolve -from django.shortcuts import get_object_or_404, redirect +from django.shortcuts import get_object_or_404, redirect, Http404 from django.utils.translation import gettext_lazy as _ from django.core.exceptions import PermissionDenied from django.contrib.auth.mixins import LoginRequiredMixin @@ -44,7 +44,6 @@ class DashboardView(LoginRequiredMixin): return context def get_session_devices(self): - # import pdb; pdb.set_trace() dev_ids = self.request.session.pop("devices", []) self._devices = [] @@ -82,3 +81,28 @@ class InventaryMixin(DashboardView, TemplateView): except Exception: pass return super().get(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + limit = self.request.GET.get("limit", 10) + page = self.request.GET.get("page", 1) + if limit: + try: + limit = int(limit) + page = int(page) + except: + raise Http404 + + offset = (page - 1) * limit + devices, count = self.get_devices(self.request.user, offset, limit) + total_pages = (count + limit - 1) // limit + + context.update({ + 'devices': devices, + 'count': count, + "limit": limit, + "offset": offset, + "page": page, + "total_pages": total_pages, + }) + return context diff --git a/dashboard/templates/unassigned_devices.html b/dashboard/templates/unassigned_devices.html index c21a2be..cb8a42c 100644 --- a/dashboard/templates/unassigned_devices.html +++ b/dashboard/templates/unassigned_devices.html @@ -1,5 +1,7 @@ {% extends "base.html" %} {% load i18n %} +{% load paginacion %} + {% block content %}
@@ -55,4 +57,9 @@
+
+
+ {% render_pagination page total_pages %} +
+
{% endblock %} diff --git a/dashboard/templatetags/__init__.py b/dashboard/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dashboard/templatetags/paginacion.py b/dashboard/templatetags/paginacion.py new file mode 100644 index 0000000..7a50113 --- /dev/null +++ b/dashboard/templatetags/paginacion.py @@ -0,0 +1,19 @@ +from django import template + +register = template.Library() + +@register.inclusion_tag('pagination.html') +def render_pagination(page_number, total_pages): + """ + Template tag for render pagination + + Args: + - page_number: number of actual page + - total_pages: total pages. + + Use it template: {% render_pagination page_number total_pages %} + """ + return { + 'page_number': page_number, + 'total_pages': total_pages, + } diff --git a/dashboard/templatetags/range.py b/dashboard/templatetags/range.py new file mode 100644 index 0000000..7e4a724 --- /dev/null +++ b/dashboard/templatetags/range.py @@ -0,0 +1,23 @@ +from django import template + +register = template.Library() + + +@register.filter +def range_filter(value, page): + m = 11 + mind = page -1 - m // 2 + maxd = page + 1 + m // 2 + if mind < 0: + maxd += abs(mind) + if maxd > value: + mind -= abs(maxd-value-1) + total_pages = [x for x in range(1, value + 1) if maxd > x > mind] + + if value > m: + if total_pages[0] > 1: + total_pages = ["..."] + total_pages + if total_pages[-1] < value: + total_pages = total_pages + ["..."] + + return total_pages diff --git a/dashboard/views.py b/dashboard/views.py index 79b9346..5384cc4 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -1,4 +1,6 @@ from django.utils.translation import gettext_lazy as _ +from django.shortcuts import Http404 + from dashboard.mixins import InventaryMixin, DetailsMixin from device.models import Device from lot.models import Lot @@ -10,15 +12,8 @@ class UnassignedDevicesView(InventaryMixin): title = _("Unassigned Devices") breadcrumb = "Devices / Unassigned Devices" - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - devices = Device.get_unassigned(self.request.user) - - context.update({ - 'devices': devices, - }) - - return context + def get_devices(self, user, offset, limit): + return Device.get_unassigned(self.request.user, offset, limit) class LotDashboardView(InventaryMixin, DetailsMixin): @@ -30,14 +25,12 @@ class LotDashboardView(InventaryMixin, DetailsMixin): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - devices = self.get_devices() lot = context.get('object') context.update({ - 'devices': devices, 'lot': lot, }) return context - def get_devices(self): + def get_devices(self, user, offset, limit): chids = self.object.devicelot_set.all().values_list("device_id", flat=True).distinct() - return [Device(id=x) for x in chids] + return [Device(id=x) for x in chids], chids.count() diff --git a/device/models.py b/device/models.py index f1b1ee7..6264130 100644 --- a/device/models.py +++ b/device/models.py @@ -1,4 +1,4 @@ -from django.db import models +from django.db import models, connection from utils.constants import STR_SM_SIZE, STR_SIZE, STR_EXTEND_SIZE, ALGOS from evidence.models import Annotation, Evidence @@ -113,17 +113,46 @@ class Device: self.lots = [x.lot for x in DeviceLot.objects.filter(device_id=self.id)] @classmethod - def get_unassigned(cls, user): - chids = DeviceLot.objects.filter(lot__owner=user).values_list("device_id", flat=True).distinct() - annotations = Annotation.objects.filter( - owner=user, - type=Annotation.Type.SYSTEM, - ).exclude(value__in=chids).values_list("value", flat=True).distinct() - return [cls(id=x) for x in annotations] + def get_unassigned(cls, user, offset=0, limit=None): - # return cls.objects.filter( - # owner=user - # ).annotate(num_lots=models.Count('lot')).filter(num_lots=0) + sql = """ + SELECT DISTINCT t1.value from evidence_annotation as t1 + left join lot_devicelot as t2 on t1.value = t2.device_id + where t2.device_id is null and owner_id=={user} and type=={type} + """.format( + user=user.id, + type=Annotation.Type.SYSTEM, + ) + if limit: + sql += " limit {} offset {}".format(int(limit), int(offset)) + + sql += ";" + + annotations = [] + with connection.cursor() as cursor: + cursor.execute(sql) + annotations = cursor.fetchall() + + devices = [cls(id=x[0]) for x in annotations] + count = cls.get_unassigned_count(user) + return devices, count + + + @classmethod + def get_unassigned_count(cls, user): + + sql = """ + SELECT count(DISTINCT t1.value) from evidence_annotation as t1 + left join lot_devicelot as t2 on t1.value = t2.device_id + where t2.device_id is null and owner_id=={user} and type=={type}; + """.format( + user=user.id, + type=Annotation.Type.SYSTEM, + ) + + with connection.cursor() as cursor: + cursor.execute(sql) + return cursor.fetchall()[0][0] @property def is_websnapshot(self): diff --git a/prevision.txt b/prevision.txt deleted file mode 100644 index b1ad84d..0000000 --- a/prevision.txt +++ /dev/null @@ -1,23 +0,0 @@ -4 login -8 device models -4 inventory template -4 upload snapshots -16 parse snapshots -16 build devices -8 action models -8 view actions -8 lot models -16 view lots -8 edit device -16 documents -8 tag -8 print label -4 server erase -4 profile -8 erase views -8 erase certificate -4 inventory snapshots -8 search -join split devices - -168 horas => 21 dias