1.分页方式:
bootstrap-table提供两种分页方式,client和server,即客户端和服务端分页;
特点:
弊端:
client端分页:
server端分页:
暂无
在你的base模板中引入相应的包即可使用,这里代码就不全贴出来了
{% extends "base.html" %}
{% load static %}
{% block main %}
<style>
.table th, .table td {
text-align: center;
vertical-align: middle !important;
word-break: break-all;
}
</style>
<!-- Basic Setup -->
<section class="section">
<div class="container mt-100">
<div class="row justify-content-center">
<div class="col-12 text-center">
<div class="section-title mb-4 pb-2">
<h4 class="title mb-4">xxxxxxxx列表</h4>
</div>
</div><!--end col-->
</div><!--end row-->
<div id="toolbar">
<div class="form-inline" role="form">
<input class="btn btn-soft-primary btn-sm" type="button" id="btn1" value="显示所有列"
onclick="showAllCol()">
<a href="{% url 'feature_extension:new_feature' %}" target="_blank" style="margin-left: 5px"><input
class="btn btn-soft-secondary btn-sm" type="button" id="btn2" value="增加新申请"
href="{% url 'feature_extension:new_feature' %}"></a>
<!-- 自定义搜索查询 -->
<div class="input-group" style="left: 5px"><input id="search-keyword"
class="form-control search-input" type="search"
placeholder="Search" autocomplete="off">
<div class="input-group-append">
<button id="search-button" class="btn btn-soft-primary btn-sm" type="button" name="search"
title="Search">
<i class="fa fa-search"></i></button>
</div>
</div>
</div>
</div>
<!-- data feature index pagination -->
<table id="table"
class="table-sm small"
data-pagination="true"
data-buttons-class="soft-primary btn-sm"
data-sort-name="created_date"
data-sort-order="desc"
data-remember-order="true"
data-show-fullscreen="true"
data-show-columns="true"
data-show-columns-toggle-all="true"
data-show-export="true"
data-click-to-select="true"
data-toolbar="#toolbar"
style="table-layout: fixed;height: auto"
>
<thead class="thead-light">
</table>
</div>
</section>
{% endblock %}
{% block script %}
<!-- JS for download table-->
<script>
var $table = $('#table')
$(function () {
$('#toolbar').find('select').change(function () {
$table.bootstrapTable('destroy').bootstrapTable({
exportDataType: $(this).val(),
exportTypes: ['excel', 'xml', 'csv', 'txt', 'sql'],
columns: [
{
field: 'state',
checkbox: true,
visible: $(this).val() === 'selected'
}
]
})
}).trigger('change')
})
</script>
<!-- JS for pagination -->
<script>
var $articlesTable = $('#table').bootstrapTable('destroy').bootstrapTable({
url: '/feature_extension/feature_extension_list/',
method: 'GET',
dataType: "json",
uniqueId: 'id', //每一行的唯一标识,一般为主键列
striped: false, //是否显示行间隔色
cache: false,
sortName: 'no',
sortable: true,
sortOrder: 'desc',
sidePagination: "server",
undefinedText: '--',
singleSelect: true,
toolbar: '#toolbar', //工具按钮用哪个容器
showToggle: true, //是否显示详细视图和列表视图的切换按钮
cardView: false, //是否显示详细视图
strictSearch: true,
clickToSelect: true,
pagination: true, //是否显示分页(*)
showRefresh: true, //是否显示刷新按钮
pageNumber: 1, //初始化加载第一页,默认第一页
pageSize: 10, //每页的记录行数(*)
pageList: [10, 20, 50, 100, 'all'],
paginationPreText: "<",
paginationNextText: ">",
queryParamsType: "",
queryParams: function (params) {
var query_params = {
'pageSize': params.pageSize,
'pageNumber': params.pageNumber,
'search_kw': $('#search-keyword').val(), // 查询框中的参数传递给后台
'sortName': params.sortName,
'sortOrder': params.sortOrder
};
return query_params;
},
columns: [
{
field: 'no',
title: '序号',
align: 'center',
halign: 'center',
width: '60px',
visible: true,
sortable: true,
formatter: function (value, row, index) {
var result = "";
result += '<a href="/feature_extension/edit_feature/' + row.id + '/" target="_blank">' + row.no + '</a>'
return result
}
},
{
field: 'id',
title: 'DB_Id',
align: 'center',
halign: 'center',
width: '70px',
visible: false,
sortable: true,
formatter: function (value, row, index) {
var result = "";
result += '<a href="/feature_extension/edit_feature/' + row.id + '/" target="_blank">' + row.id + '</a>'
return result
}
},
{
field: 'title',
title: '主题',
align: 'left',
halign: 'center',
width: '180px',
visible: true,
formatter: function (value, row, index) {
var result = "";
result += '<a href="/feature_extension/edit_feature/' + row.id + '/" target="_blank">' + row.title + '</a>'
return result
}
},
{
field: 'owner',
title: '申请人ID',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'full_name',
title: '申请人',
align: 'left',
halign: 'center',
width: '100px',
visible: true,
},
{
field: 'category',
title: '类别',
align: 'left',
halign: 'center',
width: '80px',
visible: true,
},
{
field: 'description',
title: '描述',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'oecc_domestic',
title: 'OCL国内',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
formatter: function (value, row, index) {
var result = "";
for (var i = 0; i < row.oecc_domestic.length; i++) {
result += '<span>'+row.oecc_domestic[i].name+'; </span>'
}
return result
}
},
{
field: 'oecc_oversea',
title: 'OCL海外',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
formatter: function (value, row, index) {
var result = "";
for (var i = 0; i < row.oecc_oversea.length; i++) {
result += '<span>'+row.oecc_oversea[i].name+'; </span>'
}
return result
}
},
{
field: 'oe_domestic',
title: 'OE国内',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
formatter: function (value, row, index) {
var result = "";
for (var i = 0; i < row.oe_domestic.length; i++) {
result += '<span>'+row.oe_domestic[i].name+'; </span>'
}
return result
}
},
{
field: 'oe_oversea',
title: 'OE海外',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
formatter: function (value, row, index) {
var result = "";
for (var i = 0; i < row.oe_oversea.length; i++) {
result += '<span>'+row.oe_oversea[i].name+'; </span>'
}
return result
}
},
{
field: 'note',
title: '备注',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'tech_ss',
title: '受影响子系统',
align: 'left',
halign: 'center',
width: '100px',
visible: true,
formatter: function (value, row, index) {
var result = "";
for (var i = 0; i < row.tech_ss.length; i++) {
result += '<span>'+row.tech_ss[i].name+'; </span>'
}
return result
}
},
{
field: 'solution',
title: '技术可行性',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'complexity',
title: '复杂度',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'tech_comment',
title: '技术团队建议',
align: 'left',
halign: 'center',
width: '100px',
visible: true,
},
{
field: 'mkt_decision',
title: '市场部决策',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
formatter: function (value, row, index) {
{#console.log(row)#}
var result = "";
{#for (var i = 0; i < row.tech_ss.length; i++) {#}
{# result += '<span>'+row.tech_ss[i].name+'; </span>'#}
{#}#}
return result
}
},
{
field: 'mkt_priority',
title: '优先级',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'mkt_comment',
title: '市场团队建议',
align: 'left',
halign: 'center',
width: '100px',
visible: true,
},
{
field: 'status',
title: '进度状态',
align: 'center',
halign: 'center',
width: '80px',
visible: true,
},
{
field: 'plan',
title: '计划发布时间',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'exe_owner',
title: '项目负责人',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'exe_owner_mail',
title: '邮箱',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'exe_leader_mail',
title: '经理邮箱',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'cr_number',
title: 'CR',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'cn_number',
title: 'CN',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'mrd_date',
title: 'MRD',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
},
{
field: 'created_date',
title: '创建日期',
align: 'center',
halign: 'center',
width: '100px',
visible: true,
sortable: true,
},
{
field: 'attachments',
title: '附件',
align: 'left',
halign: 'center',
width: '100px',
visible: false,
formatter: function (value, row, index) {
var result = "";
for (var i = 0; i < row.attachments.length; i++) {
result += '<a href="/file/feature_extension_file_download/' + row.attachments[i].id + '">' + row.attachments[i].filename + ';<br/></a>'
}
return result
}
},
{
title: '操作',
align: 'center',
halign: 'center',
width: '50px',
visible: true,
formatter: function (value, row, index) {
var result = "";
result += '<a href="/feature_extension/edit_feature/' + row.id + '/" target="_blank"><i class="fas fa-edit"></i></a> '
result += '<a href="#" οnclick="del_feature_ext(' + row.id + ')"><i class="fas fa-trash-alt"></i></a>'
return result
}
}
],
onLoadError: function (data) {
console.log("数据加载失败!", "错误提示");
$.messager.alert({title: '提示', msg: '数据加载失败!', icon: 'warning', top: 200});
},
});
// 搜索查询按钮触发事件
$("#search-button").click(function () {
console.log($('#search-keyword').val())
$('#table').bootstrapTable(('refresh'));
})
// 回车执行搜索
$("#search-keyword").bind('keyup', function (event) {
console.log($('#search-keyword').val())
$('#table').bootstrapTable(('refresh'));
})
</script>
<!-- JS for delete data -->
<script>
function del_feature_ext(feature_id) {
console.log(feature_id)
$.messager.confirm({
title: '提示', msg: '是否确认删除该条数据?', top: 200, fn: function (r) {
if (r) {
$.ajax({
url: server_url + '/feature_extension/del_feature/' + feature_id,
method: 'GET',
processData: false,
contentType: false,
cache: false,
success: function (data) {
console.log("data:" + data);
console.log("data:" + data.status);
if (data.status === 200) {
{#$.messager.alert({title: '提示', msg: data.msg, icon: 'warning', top: 200,});#}
$.messager.show({
title: '提示',
msg: data.msg,
showType: '',
timeout: 500,
style: {top: 200}
});
console.log("data:" + data.msg);
{#window.setTimeout(window.location = server_url + '/cp_index/', 2500);#}
window.setTimeout("window.location=server_url+'/feature_extension'", 600);
return
}
console.log(data)
$.messager.alert({title: '提示', msg: '权限不足或服务请求异常,数据无法删除!', icon: 'warning', top: 200});
},
//请求失败,包含具体的错误信息
error: function (data) {
console.log('error' + data.msg);
$.messager.alert({title: '提示', msg: '请求服务错误或当前网络不佳!', icon: 'warning', top: 200});
}
});
}
}
});
}
</script>
<!-- JS for show/hide column-->
<script>
var showFlag = true
function showAllCol() {
if (showFlag) {
$table.bootstrapTable('showColumn', 'category');
$table.bootstrapTable('showColumn', 'description');
$table.bootstrapTable('showColumn', 'full_name');
$table.bootstrapTable('showColumn', 'owner');
$table.bootstrapTable('showColumn', 'oecc_domestic');
$table.bootstrapTable('showColumn', 'oecc_oversea');
$table.bootstrapTable('showColumn', 'oe_domestic');
$table.bootstrapTable('showColumn', 'oe_oversea');
$table.bootstrapTable('showColumn', 'note');
$table.bootstrapTable('showColumn', 'tech_ss');
$table.bootstrapTable('showColumn', 'solution');
$table.bootstrapTable('showColumn', 'complexity');
$table.bootstrapTable('showColumn', 'tech_comment');
$table.bootstrapTable('showColumn', 'mkt_decision');
$table.bootstrapTable('showColumn', 'mkt_priority');
$table.bootstrapTable('showColumn', 'mkt_comment');
$table.bootstrapTable('showColumn', 'plan');
$table.bootstrapTable('showColumn', 'exe_owner');
$table.bootstrapTable('showColumn', 'exe_owner_mail');
$table.bootstrapTable('showColumn', 'exe_leader_mail');
$table.bootstrapTable('showColumn', 'cr_number');
$table.bootstrapTable('showColumn', 'cn_number');
$table.bootstrapTable('showColumn', 'attachments');
showFlag = false
} else {
$table.bootstrapTable('hideColumn', 'description');
$table.bootstrapTable('hideColumn', 'owner');
$table.bootstrapTable('hideColumn', 'oecc_domestic');
$table.bootstrapTable('hideColumn', 'oecc_oversea');
$table.bootstrapTable('hideColumn', 'oe_domestic');
$table.bootstrapTable('hideColumn', 'oe_oversea');
$table.bootstrapTable('hideColumn', 'note');
$table.bootstrapTable('hideColumn', 'solution');
$table.bootstrapTable('hideColumn', 'complexity');
$table.bootstrapTable('hideColumn', 'mkt_decision');
$table.bootstrapTable('hideColumn', 'mkt_priority');
$table.bootstrapTable('hideColumn', 'plan');
$table.bootstrapTable('hideColumn', 'exe_owner');
$table.bootstrapTable('hideColumn', 'exe_owner_mail');
$table.bootstrapTable('hideColumn', 'exe_leader_mail');
$table.bootstrapTable('hideColumn', 'cr_number');
$table.bootstrapTable('hideColumn', 'cn_number');
$table.bootstrapTable('hideColumn', 'attachments');
showFlag = true
}
}
</script>
{% endblock %}
APIView使用了DRF框架,django内置的是View
查询功能可根据自己的需求更改
模型表models.py
class feature_ext(BaseModel):
# properties for applicant
title = models.CharField(max_length=200, verbose_name='主题', blank=False)
owner = models.CharField(max_length=50,
blank=True,
verbose_name='申请人ID')
full_name = models.CharField(max_length=50,
blank=False,
verbose_name='申请人')
category = models.CharField(max_length=10,
blank=False,
choices=[('', '请选择'), ('NEW', '新需求'), ('NONSTD', '非标转标准化')],
verbose_name='类别')
description = models.TextField(blank=False, verbose_name='描述')
oecc_domestic = models.ManyToManyField(OeccDomestic, blank=True, verbose_name="OCL国内产品:")
oecc_oversea = models.ManyToManyField(OeccOversea, blank=True, verbose_name="OCL海外产品:")
oe_domestic = models.ManyToManyField(OeDomestic, blank=True, verbose_name="OE国内产品:")
oe_oversea = models.ManyToManyField(OeOversea, blank=True, verbose_name="OE海外产品:")
note = models.TextField(blank=True, verbose_name='备注')
# properties for evaluator
# Technical Review 技术团队评估
tech_ss = models.ManyToManyField(subsystem, blank=True, verbose_name="受影响子系统:")
solution = models.CharField(max_length=10,
blank=True,
choices=[('', '请选择'), ('Y', '有'), ('N', '无')],
verbose_name='技术可行性-成熟的技术方案(有/无)')
complexity = models.CharField(max_length=10,
blank=True,
choices=[('', '请选择'), ('H', '高'), ('M', '中'), ('L', '低')],
verbose_name='复杂度')
tech_comment = models.TextField(blank=True, verbose_name='技术团队建议')
# Marketing Review 产品管理团队评估
mkt_decision = models.CharField(max_length=10,
blank=True,
choices=[('', '请选择'), ('GO', '同意'), ('GO_A', '同意并有行动项'),
('MEETING', '会议讨论'),
('NO', '拒绝')],
verbose_name='市场部决策')
mkt_priority = models.CharField(max_length=10,
blank=True,
choices=[('', '请选择'), ('H', '高'), ('M', '中'), ('L', '低')],
verbose_name='优先级')
mkt_comment = models.TextField(blank=True, verbose_name='市场团队建议')
# Conclusion 结论
# final_decision = models.TextField(blank=True, verbose_name='决策及产品管理团队建议')
# Executor 执行方
plan = models.DateField(null=True, blank=True, verbose_name='计划发布时间')
exe_owner = models.CharField(max_length=50,
blank=True,
verbose_name='项目负责人')
exe_owner_mail = models.EmailField(max_length=100,
blank=True,
verbose_name='邮箱')
exe_leader_mail = models.EmailField(max_length=100,
blank=True,
verbose_name='经理邮箱')
cr_number = models.CharField(max_length=200,
blank=True,
verbose_name='CR')
cn_number = models.CharField(max_length=200,
blank=True,
verbose_name='CN')
mrd_date = models.DateField(null=True, blank=True, verbose_name='MRD')
exe_comment = models.CharField(max_length=1000,
blank=True,
null=True,
verbose_name='备注')
invalid_prd = models.CharField(max_length=500,
blank=True,
null=True,
verbose_name='Invalid Products')
# 添加user, file外键
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)
attachments = models.ManyToManyField(FeatureExtensionFile, blank=True)
status = models.CharField(max_length=100,
blank=True,
null=True,
choices=[('0', '新需求'), ('1', '技术评估'), ('2', '市场评估'), ('3', '评估结论'), ('4', '实施计划')],
verbose_name='状态')
class Meta:
ordering = ['-id']
def __str__(self):
return self.title
序列化器serializer.py
class OeccDomesticSerializer(ModelSerializer):
class Meta:
model = OeccDomestic
fields = '__all__'
class OeccDomesticField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
if not value:
return None
obj = OeccDomestic.objects.get(pk=value.pk)
if obj:
data = OeccDomesticSerializer(obj).data
return data
class OeccOverseaSerializer(ModelSerializer):
class Meta:
model = OeccOversea
fields = '__all__'
class OeccOverseaField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
if not value:
return None
obj = OeccOversea.objects.get(pk=value.pk)
if obj:
data = OeccOverseaSerializer(obj).data
return data
class OeDomesticSerializer(ModelSerializer):
class Meta:
model = OeDomestic
fields = '__all__'
class OeDomesticField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
if not value:
return None
obj = OeDomestic.objects.get(pk=value.pk)
if obj:
data = OeccOverseaSerializer(obj).data
return data
class OeOverseaSerializer(ModelSerializer):
class Meta:
model = OeOversea
fields = '__all__'
class OeOverseaField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
if not value:
return None
obj = OeOversea.objects.get(pk=value.pk)
if obj:
data = OeOverseaSerializer(obj).data
return data
class FeatureExtensionQuerySerializer(ModelSerializer):
category = serializers.SerializerMethodField()
solution = serializers.SerializerMethodField()
complexity = serializers.SerializerMethodField()
mkt_decision = serializers.SerializerMethodField()
mkt_priority = serializers.SerializerMethodField()
status = serializers.SerializerMethodField()
# 多对多字段序列化
oecc_domestic = OeccDomesticField(queryset=OeccDomestic.objects.all(), many=True)
oecc_oversea = OeccOverseaField(queryset=OeccOversea.objects.all(), many=True)
oe_domestic = OeDomesticField(queryset=OeDomestic.objects.all(), many=True)
oe_oversea = OeOverseaField(queryset=OeOversea.objects.all(), many=True)
tech_ss = TechSsFiled(queryset=subsystem.objects.all(), many=True)
attachments = FeatureExtensionFileField(queryset=FeatureExtensionFile.objects.all(), many=True)
# 一对多字段序列化
user = UserField(queryset=User.objects.all())
class Meta:
model = feature_ext
fields = '__all__'
# 此处使用钩子函数是为了显示models中的元组可选字段,必须以get开头
def get_category(self, obj):
return obj.get_category_display()
def get_solution(self, obj):
return obj.get_solution_display()
def get_complexity(self, obj):
return obj.get_complexity_display()
def get_mkt_decision(self, obj):
return obj.get_mkt_decision_display()
def get_mkt_priority(self, obj):
return obj.get_mkt_priority_display()
def get_status(self, obj):
return obj.get_status_display()
视图函数views.py
class FeatureExtensionListView(APIView):
def get(self, request):
pageSize = int(request.GET.get('pageSize', 10))
pageNumber = int(request.GET.get('pageNumber', 1))
search_kw = request.GET.get('search_kw', '')
sortName = request.GET.get('sortName', '')
sortOrder = request.GET.get('sortOrder', '')
obj_all = feature_ext.objects.all()
# 查询
if search_kw:
obj_all = obj_all.filter(Q(title__icontains=search_kw) | Q(full_name__icontains=search_kw) |
Q(tech_comment__icontains=search_kw) | Q(mkt_comment__icontains=search_kw))
if sortName == 'no':
sortName = 'id'
# 方法一:直接先排序,再获取分页数据
# if sortOrder == 'desc':
# page_obj_list = obj_all.order_by('-{}'.format(sortName))[(pageNumber - 1) * pageSize:(pageNumber) * pageSize]
# else:
# page_obj_list = obj_all.order_by(sortName)[(pageNumber - 1) * pageSize:(pageNumber) * pageSize]
# 方法二:django内置分页工具类
# 1.先排序
if sortOrder == 'desc':
obj_list = obj_all.order_by('-{}'.format(sortName))
else:
obj_list = obj_all.order_by(sortName)
paginator = Paginator(obj_list, per_page=pageSize)
# 2.再获取指定页码的数据
page_obj_list = paginator.page(pageNumber)
total = obj_all.count()
rows = FeatureExtensionQuerySerializer(page_obj_list, many=True).data
page_data = get_page_all_data(total, rows, sortOrder, pageNumber, pageSize)
# print(page_data)
if page_data:
return JsonResponse(page_data)
return api_bad_request('数据加载失败!')
def get_page_all_data(total, rows, sortOrder, pageNumber, pageSize):
for i in range(len(rows)):
if sortOrder == 'desc':
no = total - (pageNumber - 1) * pageSize - i
else:
no = (pageNumber - 1) * pageSize + i + 1
rows[i]['no'] = no
data = {"total": total, "rows": rows}
return data
免责声明:以上内容和代码仅供参考!