Commit b2f97a26 authored by ibuler's avatar ibuler

[Feature] 添加后端paging

parent 59a69f02
......@@ -19,8 +19,9 @@ from rest_framework_bulk import BulkModelViewSet
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
from django.shortcuts import get_object_or_404
from django.db.models import Q
from rest_framework.pagination import LimitOffsetPagination
from common.mixins import IDInFilterMixin
from common.mixins import CustomFilterMixin
from common.utils import get_logger
from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \
get_user_granted_assets
......@@ -34,12 +35,16 @@ from .tasks import update_asset_hardware_info_manual, test_admin_user_connectabi
logger = get_logger(__file__)
class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
class AssetViewSet(CustomFilterMixin, BulkModelViewSet):
"""
API endpoint that allows Asset to be viewed or edited.
"""
filter_fields = ("hostname", "ip")
search_fields = filter_fields
ordering_fields = ("hostname", "ip", "port", "cluster", "type", "env", "cpu_cores")
queryset = Asset.objects.all()
serializer_class = serializers.AssetSerializer
pagination_class = LimitOffsetPagination
permission_classes = (IsSuperUserOrAppUser,)
def get_queryset(self):
......@@ -78,7 +83,7 @@ class UserAssetListView(generics.ListAPIView):
return queryset
class AssetGroupViewSet(IDInFilterMixin, BulkModelViewSet):
class AssetGroupViewSet(CustomFilterMixin, BulkModelViewSet):
"""
Asset group api set, for add,delete,update,list,retrieve resource
"""
......@@ -112,7 +117,7 @@ class GroupAddAssetsApi(generics.UpdateAPIView):
return Response({'error': serializer.errors}, status=400)
class ClusterViewSet(IDInFilterMixin, BulkModelViewSet):
class ClusterViewSet(CustomFilterMixin, BulkModelViewSet):
"""
Cluster api set, for add,delete,update,list,retrieve resource
"""
......@@ -153,7 +158,7 @@ class ClusterAddAssetsApi(generics.UpdateAPIView):
return Response({'error': serializer.errors}, status=400)
class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet):
class AdminUserViewSet(CustomFilterMixin, BulkModelViewSet):
"""
Admin user api set, for add,delete,update,list,retrieve resource
"""
......@@ -189,7 +194,7 @@ class SystemUserViewSet(BulkModelViewSet):
permission_classes = (IsSuperUserOrAppUser,)
class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
class AssetListUpdateApi(CustomFilterMixin, ListBulkCreateUpdateDestroyAPIView):
"""
Asset bulk update api
"""
......
......@@ -71,10 +71,21 @@ function initTable() {
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
console.log('{{ the_url }}');
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 4, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.cluster_name)
}},
{targets: 5, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.get_type_display)
}},
{targets: 6, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.get_env_display)
}},
{targets: 7, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.hardware_info)
}},
{targets: 8, createdCell: function (td, cellData) {
if (!cellData) {
$(td).html('<i class="fa fa-times text-danger"></i>')
......@@ -98,12 +109,15 @@ function initTable() {
}}
],
ajax_url: '{% url "api-assets:asset-list" %}',
columns: [{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" }, {data: "cluster_name"},
{data: "get_type_display" }, {data: "get_env_display"}, {data: "hardware_info"},
{data: "is_active" }, {data: "is_connective"}, {data: "id" }],
columns: [
{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" },
{data: "cluster"}, {data: "type" }, {data: "env"},
{data: "cpu_cores"}, {data: "is_active", orderable: false },
{data: "is_connective", orderable: false}, {data: "id", orderable: false }
],
op_html: $('#actions').html()
};
return jumpserver.initDataTable(options);
return jumpserver.initServerSideDataTable(options);
}
$(document).ready(function(){
......
......@@ -47,8 +47,9 @@ class JSONResponseMixin(object):
return JsonResponse(context)
class IDInFilterMixin(object):
class CustomFilterMixin(object):
def filter_queryset(self, queryset):
queryset = super(CustomFilterMixin, self).filter_queryset(queryset)
id_list = self.request.query_params.get('id__in')
if id_list:
import json
......
......@@ -288,9 +288,17 @@ REST_FRAMEWORK = {
'users.authentication.PrivateTokenAuthentication',
'users.authentication.SessionAuthentication',
),
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
),
'ORDERING_PARAM': "order",
'SEARCH_PARAM': "search",
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S %z',
'DATETIME_INPUT_FORMATS': ['%Y-%m-%d %H:%M:%S %z'],
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 15
}
AUTHENTICATION_BACKENDS = [
......
......@@ -330,6 +330,120 @@ jumpserver.initDataTable = function (options) {
return table;
};
jumpserver.initServerSideDataTable = function (options) {
// options = {
// ele *: $('#dataTable_id'),
// ajax_url *: '{% url 'users:user-list-api' %}',
// columns *: [{data: ''}, ....],
// dom: 'fltip',
// i18n_url: '{% static "js/...../en-us.json" %}',
// order: [[1, 'asc'], [2, 'asc'], ...],
// buttons: ['excel', 'pdf', 'print'],
// columnDefs: [{target: 0, createdCell: ()=>{}}, ...],
// uc_html: '<a>header button</a>',
// op_html: 'div.btn-group?',
// paging: true
// }
var ele = options.ele || $('.dataTable');
var columnDefs = [
{
targets: 0,
orderable: false,
createdCell: function (td, cellData) {
$(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData));
}
},
{className: 'text-center', targets: '_all'}
];
columnDefs = options.columnDefs ? options.columnDefs.concat(columnDefs) : columnDefs;
var select = {
style: 'multi',
selector: 'td:first-child'
};
var table = ele.DataTable({
pageLength: options.pageLength || 15,
dom: options.dom || '<"#uc.pull-left">flt<"row m-t"<"col-md-8"<"#op.col-md-6"><"col-md-6 text-center"i>><"col-md-4"p>>',
order: options.order || [],
// select: options.select || 'multi',
buttons: [],
columnDefs: columnDefs,
serverSide: true,
processing: true,
ajax: {
url: options.ajax_url ,
data: function (data) {
delete data.columns;
var length = data.length;
if (data.length !== null ){
data.limit = data.length;
delete data.length;
}
if (data.start !== null) {
data.offset = data.start;
delete data.start;
}
if (data.search !== null) {
var search_val = data.search.value;
data.search = search_val;
}
if (data.order !== null && data.order.length === 1) {
var col = data.order[0].column;
var order = options.columns[col].data;
if (data.order[0].dir = "desc") {
order = "-" + order;
}
data.order = order;
}
},
dataSrc: "results"
},
columns: options.columns || [],
select: options.select || select,
language: {
search: "搜索",
lengthMenu: "每页 _MENU_",
info: "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项",
infoFiltered: "",
infoEmpty: "",
zeroRecords: "没有匹配项",
emptyTable: "没有记录",
paginate: {
first: "«",
previous: "‹",
next: "›",
last: "»"
}
},
lengthMenu: [[15, 25, 50, -1], [15, 25, 50, "All"]]
});
table.on('select', function(e, dt, type, indexes) {
var $node = table[ type ]( indexes ).nodes().to$();
$node.find('input.ipt_check').prop('checked', true);
jumpserver.selected[$node.find('input.ipt_check').prop('id')] = true
}).on('deselect', function(e, dt, type, indexes) {
var $node = table[ type ]( indexes ).nodes().to$();
$node.find('input.ipt_check').prop('checked', false);
jumpserver.selected[$node.find('input.ipt_check').prop('id')] = false
}).
on('draw', function(){
$('#op').html(options.op_html || '');
$('#uc').html(options.uc_html || '');
});
$('.ipt_check_all').on('click', function() {
if (!jumpserver.checked) {
$(this).closest('table').find('.ipt_check').prop('checked', true);
jumpserver.checked = true;
table.rows({search:'applied'}).select();
} else {
$(this).closest('table').find('.ipt_check').prop('checked', false);
jumpserver.checked = false;
table.rows({search:'applied'}).deselect();
}
});
return table;
};
/**
* 替换所有匹配exp的字符串为指定字符串
* @param exp 被替换部分的正则
......
......@@ -13,14 +13,14 @@ from .tasks import write_login_log_async
from .models import User, UserGroup
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
from .utils import check_user_valid, generate_token
from common.mixins import IDInFilterMixin
from common.mixins import CustomFilterMixin
from common.utils import get_logger
logger = get_logger(__name__)
class UserViewSet(IDInFilterMixin, BulkModelViewSet):
class UserViewSet(CustomFilterMixin, BulkModelViewSet):
queryset = User.objects.exclude(role="App")
# queryset = User.objects.all().exclude(role="App").order_by("date_joined")
serializer_class = UserSerializer
......@@ -72,7 +72,7 @@ class UserUpdatePKApi(generics.UpdateAPIView):
user.save()
class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet):
class UserGroupViewSet(CustomFilterMixin, BulkModelViewSet):
queryset = UserGroup.objects.all()
serializer_class = UserGroupSerializer
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment