From dc2a8cb462ef5eb7333ab9a49788969661eac80b Mon Sep 17 00:00:00 2001 From: bashmak Date: Wed, 7 Feb 2018 16:07:38 +0300 Subject: [PATCH] Refactoring vedapp.views.devices view to ClassBasedView. Also add OrderingMixin for ordering. And update ordering template. Changed files in commit changed: README.md changed: devapp/templates/devapp/devices.html changed: devapp/urls.py changed: devapp/views.py changed: djing/global_base_views.py new file: docs/img/pagination.png new file: docs/views.md changed: mydefs.py new file: templates/toolbar_page_cbv.html --- README.md | 1 + devapp/templates/devapp/devices.html | 8 ++-- devapp/urls.py | 2 +- devapp/views.py | 53 +++++++++++++------------ djing/global_base_views.py | 30 ++++++++++++++ docs/img/pagination.png | Bin 0 -> 1297 bytes docs/views.md | 56 +++++++++++++++++++++++++++ mydefs.py | 1 + templates/toolbar_page_cbv.html | 26 +++++++++++++ 9 files changed, 148 insertions(+), 29 deletions(-) create mode 100644 docs/img/pagination.png create mode 100644 docs/views.md create mode 100644 templates/toolbar_page_cbv.html diff --git a/README.md b/README.md index f49de3c..dd2f36a 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,4 @@ P.S. Возможно понадобится **Python 3.5** и выше из-з * [Установка](./docs/install.md) * [Разработка расширений](./docs/dev.md) * [Сбор информации трафика по netflow](./docs/netflow.md) +* [Работа с представлениями](./docs/views.md) diff --git a/devapp/templates/devapp/devices.html b/devapp/templates/devapp/devices.html index 2316576..e9a8068 100644 --- a/devapp/templates/devapp/devices.html +++ b/devapp/templates/devapp/devices.html @@ -17,13 +17,13 @@ # - + {% trans 'Ip address' %} {% if order_by == 'ip_address' %}{% endif %} - + {% trans 'Comment' %} {% if order_by == 'comment' %}{% endif %} @@ -31,7 +31,7 @@ {% trans 'Mac address' %} {# {% trans 'Plugin output' %} #} - + {% trans 'Device type' %} {% if order_by == 'devtype' %}{% endif %} @@ -96,6 +96,6 @@ - {% include 'toolbar_page.html' with pag=devices %} + {% include 'toolbar_page_cbv.html' %} {% endblock %} diff --git a/devapp/urls.py b/devapp/urls.py index 0412f33..efa5c1c 100644 --- a/devapp/urls.py +++ b/devapp/urls.py @@ -9,7 +9,7 @@ urlpatterns = [ url(r'^$', views.group_list, name='group_list'), url(r'^devices_without_groups$', views.devices_null_group, name='devices_null_group'), url(r'^fix_onu/$', views.fix_onu, name='fix_onu'), - url(r'^(?P\d+)$', views.devices, name='devs'), + url(r'^(?P\d+)$', views.DevicesListView.as_view(), name='devs'), url(r'^(?P\d+)/add$', views.dev, name='add'), url(r'^(\d+)/(?P\d+)$', views.devview, name='view'), url(r'^(\d+)/(?P\d+)/del$', views.devdel, name='del'), diff --git a/devapp/views.py b/devapp/views.py index 537ac48..08bf2f1 100644 --- a/devapp/views.py +++ b/devapp/views.py @@ -11,6 +11,7 @@ from django.contrib import messages from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _, gettext from easysnmp import EasySNMPTimeoutError, EasySNMPError +from django.views.generic import ListView from mydefs import pag_mn, res_success, res_error, only_admins, ping, order_helper, ip_addr_regex from abonapp.models import AbonGroup, Abon @@ -20,38 +21,42 @@ from guardian.shortcuts import get_objects_for_user from chatbot.telebot import send_notify from chatbot.models import ChatException from jsonview.decorators import json_view -from djing.global_base_views import HashAuthView, AllowedSubnetMixin +from djing.global_base_views import HashAuthView, AllowedSubnetMixin, OrderingMixin from .models import Device, Port, DeviceDBException, DeviceMonitoringException from .forms import DeviceForm, PortForm +from mydefs import safe_int -@login_required -@only_admins -def devices(request, group_id): - group = get_object_or_404(AbonGroup, pk=group_id) - if not request.user.has_perm('abonapp.can_view_abongroup', group): - raise PermissionDenied - try: - devs = Device.objects.filter(user_group=group) \ - .select_related('user_group') \ - .only('comment', 'mac_addr', 'devtype', 'user_group', 'pk', 'ip_address') +PAGINATION_ITEMS_PER_PAGE = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) - dr, field = order_helper(request) - if field: - devs = devs.order_by(field) - devs = pag_mn(request, devs) - #devs = Device.objects.wrap_monitoring_info(devs) +@method_decorator([login_required, only_admins], name='dispatch') +class DevicesListView(ListView, OrderingMixin): + context_object_name = 'devices' + template_name = 'devapp/devices.html' + paginate_by = PAGINATION_ITEMS_PER_PAGE + http_method_names = ['get'] - except (DeviceDBException, DeviceMonitoringException) as e: - messages.error(request, e) + def get_queryset(self): + group_id = safe_int(self.kwargs.get('group_id')) + queryset = Device.objects.filter(user_group__pk=group_id) \ + .select_related('user_group') \ + .only('comment', 'mac_addr', 'devtype', 'user_group', 'pk', 'ip_address') + return queryset - return render(request, 'devapp/devices.html', { - 'devices': devs, - 'dir': dr, - 'order_by': request.GET.get('order_by'), - 'group': group - }) + def get_context_data(self, **kwargs): + group_id = safe_int(self.kwargs.get('group_id')) + context = super(DevicesListView, self).get_context_data(**kwargs) + context['group'] = get_object_or_404(AbonGroup, pk=group_id) + return context + + def dispatch(self, request, *args, **kwargs): + try: + response = super(DevicesListView, self).dispatch(request, *args, **kwargs) + except (DeviceDBException, DeviceMonitoringException) as e: + messages.error(request, e) + response = HttpResponse('Error') + return response @login_required diff --git a/djing/global_base_views.py b/djing/global_base_views.py index c4a20e2..5eeb350 100644 --- a/djing/global_base_views.py +++ b/djing/global_base_views.py @@ -58,3 +58,33 @@ class AllowedSubnetMixin(object): return super(AllowedSubnetMixin, self).dispatch(request, *args, **kwargs) else: return HttpResponseForbidden('Access Denied') + + +class OrderingMixin(object): + """ + Ordering result object list by @order_by variable in get request. + For example url?order_by=username orders objects by username. + @dir - direction of ordering. down or up. + @order_by - ordering field name + """ + def get_context_data(self, **kwargs): + context = super(OrderingMixin, self).get_context_data(**kwargs) + context['order_by'] = self.request.GET.get('order_by') + direction = self.request.GET.get('dir') + if direction == 'down': + direction = 'up' + elif direction == 'up': + direction = 'down' + else: + direction = '' + context['dir'] = direction + return context + + def get_ordering(self): + direction = self.request.GET.get('dir') + order_by = self.request.GET.get('order_by') + dfx = '' + if direction == 'down': + dfx = '-' + if order_by: + return ["%s%s" % (dfx, order_by)] diff --git a/docs/img/pagination.png b/docs/img/pagination.png new file mode 100644 index 0000000000000000000000000000000000000000..5b9327bafc4cdf243b45cc6d4442ef437a06963a GIT binary patch literal 1297 zcmeAS@N?(olHy`uVBq!ia0vp^_kq}jgAGVBMm$&pq*#ibJVQ8upoSx*1IU*wag8Vm z&QB{TPb^AhNYBg9P1P+DR9pw62-VDZFXMiNqrUFB@INg@l|9W;Hxka^$V}c&0I9(M3t2ugfwEl}?>}uwQbb zglX}_!zV7NW~UZ!nwZn`X}Ru&J^NTs-xlYeV^$Vmc0d09ry9Qtr+>@*@{NA+d!K4_ zSe>-X6AOKY3frzPe2Z$2p1Pe->f$6JKT+VAyGqMPLC(Y)Lfk!kr7(9N{gwHAtZF_yiMurI?kK;s!aA|X?Dz*#pYW0kF`24k8kVNt$p&-t>2w7 z;L*|5RTSacY32~V=k1vkqZMn`w5)rr^f2(@#ZuXW2?DEEuf7!g?TqO8Cuh(4X3SEv zZRYA(mU-f7(IsP`=tsf3or^Tq{rhwNM@Nf+oswctzX!)-WuZd|Zin{1xMyjvU%#F) zW5$6)hnOzCG?9{)zIgHC!ykPsZ;BjSmY4ACnbn#7x*_2i75jcB+Fbpx;Bj;Y`{Up9 zBd4*(UcY$hQq#$ko*QM;)20=!xYNH}nt$<{FLr-K;tyrdKfd6Xjm5tgjvHft-`v-s zKl`jxXsAXP(`6IczpJ8LU0HA4zRk#R`SRsH+3#h{=daxVRPF3*nPh(LQ6qYAk}+lTke{*YZZk$J^ZyKcJ6umWAgvGA5U8tZ{}gB`2B@P z?Z1ar)gPyzD<4%Sd%7qInwXj@PW4ih>Rq&RXJl2FpIT(dGn8V`(JzbW=`~QFT3=&~&Zf?G0{GrZ& z@fVg|zKQ#v2#Olw%3n{Sw&m{rbx(F(#JW{lK9{G=b7Vbc;`^iKovq|`(T}ng1q>%s zgl^_syL$cE^6KLTJWDQTvM@2e)U1Bi^}dX0kEPn(Q*X_WZ~3&X`jN7hTG+j^G8%#B%504&oOJYD@<);T3K0RY+^Xwm=x literal 0 HcmV?d00001 diff --git a/docs/views.md b/docs/views.md new file mode 100644 index 0000000..f1e6bf7 --- /dev/null +++ b/docs/views.md @@ -0,0 +1,56 @@ +# Работа с представлениями + +При разработке представлений мне пришлось реализовать несколько алгоритмов, которых +нет в поставке Django. Они связаны с особенностями реализации системы. + +* [Пагинатор](#markdown-header-пагинатор) +* [Сортировка по полям объектов из списка](markdown-header-сортировка-по-полям-объектов-из-списка) + + +### Пагинатор +Есть реализованный шаблон для пагинации. При использовании [Class Based View](https://docs.djangoproject.com/en/1.11/topics/class-based-views/), +в шаблоне вы можете включить страницу *templates/toolbar_page_cbv.html*. + +Например вы создали клас представления: + +```python +from django.views.generic import ListView + +class PaysListView(ListView): + ... + pass + +``` + +Тогда в шаблоне с bootstrap вы можете увидеть примерно такую пагинацию которую +вы конечно же можете изменить на свою. +![paginator](./img/pagination.png). + + +### Сортировка по полям объектов из списка +Для того чтоб иметь возможность сортировать по полю объекта из списка, в шаблоне нужно передать +имя поля по которому нужна сортировка и направление сортировки. + +На примере *devapp/devices.html* можно рассмотреть такую сортировку. +Там указан url с параметрами +> {% url 'devapp:devs' group.pk %}?order_by=ip_address&dir={{ dir|default:'down' }} + +Тут обратная сортировка по полю *ip_address*, со знаком -. То есть эквивалент будет выглядеть примерно так: +> Device.objects.all().order_by('-ip_address') + +После того как вы отсортируете один раз, направление поменяется, в переменную dir будет передано +значение *up*, и сортировка пройдёт без знака - + +В то же время ваше представление нужно отнаследовать от OrderingMixin из *djing.global_base_views*. +Определение представления с сортировкой будет выглядеть так: + +```python +from django.views.generic import ListView +from djing.global_base_views import OrderingMixin + +class PaysListView(ListView, OrderingMixin): + ... + pass +``` + +Примесь *OrderingMixin* добавляет в контекст переменные *order_by* и *dir* для использования в шалоне. diff --git a/mydefs.py b/mydefs.py index 3189220..1e0fcba 100644 --- a/mydefs.py +++ b/mydefs.py @@ -128,6 +128,7 @@ class MyChoicesAdapter(Iterator): # через get должно быть передано order_by=<поле в бд> а в dir= направление сортировки # возвращает новое направление сортировки и поле для сортировки с направлением def order_helper(request): + print('DEPRECATION: use global_base_views.OrderingMixin') dr = request.GET.get('dir') dfx = '' if dr == 'down': diff --git a/templates/toolbar_page_cbv.html b/templates/toolbar_page_cbv.html new file mode 100644 index 0000000..4f32bd3 --- /dev/null +++ b/templates/toolbar_page_cbv.html @@ -0,0 +1,26 @@ +{% if paginator.num_pages > 1 %} +{% load dpagination %} +
+
+ +
+
+{% endif %}