mirror of https://github.com/jumpserver/jumpserver
[Feature] 添加后端paging
parent
59a69f0253
commit
b2f97a263d
|
@ -19,8 +19,9 @@ from rest_framework_bulk import BulkModelViewSet
|
||||||
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
|
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.db.models import Q
|
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 common.utils import get_logger
|
||||||
from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \
|
from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \
|
||||||
get_user_granted_assets
|
get_user_granted_assets
|
||||||
|
@ -34,12 +35,16 @@ from .tasks import update_asset_hardware_info_manual, test_admin_user_connectabi
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
|
class AssetViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||||
"""
|
"""
|
||||||
API endpoint that allows Asset to be viewed or edited.
|
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()
|
queryset = Asset.objects.all()
|
||||||
serializer_class = serializers.AssetSerializer
|
serializer_class = serializers.AssetSerializer
|
||||||
|
pagination_class = LimitOffsetPagination
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -78,7 +83,7 @@ class UserAssetListView(generics.ListAPIView):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class AssetGroupViewSet(IDInFilterMixin, BulkModelViewSet):
|
class AssetGroupViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||||
"""
|
"""
|
||||||
Asset group api set, for add,delete,update,list,retrieve resource
|
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)
|
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
|
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)
|
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
|
Admin user api set, for add,delete,update,list,retrieve resource
|
||||||
"""
|
"""
|
||||||
|
@ -189,7 +194,7 @@ class SystemUserViewSet(BulkModelViewSet):
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
|
|
||||||
|
|
||||||
class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
|
class AssetListUpdateApi(CustomFilterMixin, ListBulkCreateUpdateDestroyAPIView):
|
||||||
"""
|
"""
|
||||||
Asset bulk update api
|
Asset bulk update api
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -71,10 +71,21 @@ function initTable() {
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||||
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
|
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
|
||||||
console.log('{{ the_url }}');
|
|
||||||
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
|
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
|
||||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
$(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) {
|
{targets: 8, createdCell: function (td, cellData) {
|
||||||
if (!cellData) {
|
if (!cellData) {
|
||||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||||
|
@ -98,12 +109,15 @@ function initTable() {
|
||||||
}}
|
}}
|
||||||
],
|
],
|
||||||
ajax_url: '{% url "api-assets:asset-list" %}',
|
ajax_url: '{% url "api-assets:asset-list" %}',
|
||||||
columns: [{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" }, {data: "cluster_name"},
|
columns: [
|
||||||
{data: "get_type_display" }, {data: "get_env_display"}, {data: "hardware_info"},
|
{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" },
|
||||||
{data: "is_active" }, {data: "is_connective"}, {data: "id" }],
|
{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()
|
op_html: $('#actions').html()
|
||||||
};
|
};
|
||||||
return jumpserver.initDataTable(options);
|
return jumpserver.initServerSideDataTable(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
|
|
@ -47,8 +47,9 @@ class JSONResponseMixin(object):
|
||||||
return JsonResponse(context)
|
return JsonResponse(context)
|
||||||
|
|
||||||
|
|
||||||
class IDInFilterMixin(object):
|
class CustomFilterMixin(object):
|
||||||
def filter_queryset(self, queryset):
|
def filter_queryset(self, queryset):
|
||||||
|
queryset = super(CustomFilterMixin, self).filter_queryset(queryset)
|
||||||
id_list = self.request.query_params.get('id__in')
|
id_list = self.request.query_params.get('id__in')
|
||||||
if id_list:
|
if id_list:
|
||||||
import json
|
import json
|
||||||
|
|
|
@ -288,9 +288,17 @@ REST_FRAMEWORK = {
|
||||||
'users.authentication.PrivateTokenAuthentication',
|
'users.authentication.PrivateTokenAuthentication',
|
||||||
'users.authentication.SessionAuthentication',
|
'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_FORMAT': '%Y-%m-%d %H:%M:%S %z',
|
||||||
'DATETIME_INPUT_FORMATS': ['%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 = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
|
|
|
@ -330,6 +330,120 @@ jumpserver.initDataTable = function (options) {
|
||||||
return table;
|
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的字符串为指定字符串
|
* 替换所有匹配exp的字符串为指定字符串
|
||||||
* @param exp 被替换部分的正则
|
* @param exp 被替换部分的正则
|
||||||
|
|
|
@ -13,14 +13,14 @@ from .tasks import write_login_log_async
|
||||||
from .models import User, UserGroup
|
from .models import User, UserGroup
|
||||||
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
|
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
|
||||||
from .utils import check_user_valid, generate_token
|
from .utils import check_user_valid, generate_token
|
||||||
from common.mixins import IDInFilterMixin
|
from common.mixins import CustomFilterMixin
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(IDInFilterMixin, BulkModelViewSet):
|
class UserViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||||
queryset = User.objects.exclude(role="App")
|
queryset = User.objects.exclude(role="App")
|
||||||
# queryset = User.objects.all().exclude(role="App").order_by("date_joined")
|
# queryset = User.objects.all().exclude(role="App").order_by("date_joined")
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
|
@ -72,7 +72,7 @@ class UserUpdatePKApi(generics.UpdateAPIView):
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
|
||||||
class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet):
|
class UserGroupViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||||
queryset = UserGroup.objects.all()
|
queryset = UserGroup.objects.all()
|
||||||
serializer_class = UserGroupSerializer
|
serializer_class = UserGroupSerializer
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue