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 0000000..5b9327b
Binary files /dev/null and b/docs/img/pagination.png differ
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 вы можете увидеть примерно такую пагинацию которую
+вы конечно же можете изменить на свою.
+.
+
+
+### Сортировка по полям объектов из списка
+Для того чтоб иметь возможность сортировать по полю объекта из списка, в шаблоне нужно передать
+имя поля по которому нужна сортировка и направление сортировки.
+
+На примере *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 %}
|