在xadmin后台不使用ManyToManyField的情况下实现多对多操作,目的效果如下:
目的是将左边的公司列表可以多个或者全选加到右边,但是如果不使用ManyToManyField是不能出现上面的效果,只能这样,手动输入公司
在网上找了好久之后,发现无法实现这种控件操作,但是又想使用xadmin的数据保存、页面显示跳转等功能,只能重新写这个页面了,不过重写并不复杂,主要就是ctrl+c/v,那么开始操作吧
一、新建模板,替换原页面的模板
在pycharm中新建一个HTML文件,删掉所有信息,继承xadmin底层的表单模板
{% extends 'xadmin/views/model_form.html' %}
然后我们用这个模板把我们现在看到的替换掉,在adminx.py中你创建的那个类中加入一行代码
add_form_template = 'xxx.html'
二、重写模板
首先我们可以看一下这个model_form.html的结构
这是它的基本框架,我们要修改的就是他的content部分,所以把{% block content %}{% endblock %}部分复制到我们的模板中,同时打开目前我们的网页,将整个form部分copy进去
再看一下我们想要重新的部分如下:
先在xadmin后台看一下我们现在的网页中要修改的这一部分的class,我们可以通过选择器找到红框中的目标
那么就去使用过ManyToManyField生成的页面下把这部分代码copy出来,打开一个xadmin后台,找到之后复制element,粘贴到我们的form中< div class="controls " >的位置,同时把它的样式也复制到我们的content中
我把样式贴在这里:
<style>
.control-wrap{
display: block;
width: 100%;
padding-right: 45px;
}
.selector{
position: relative;
float: left;
overflow: hidden;
width: 100%;
}
.selector-available,.selector-chosen{
border: 1px solid #ddd;
background-color: #eee;
float: left;
width: 45%;
}
.selector p.title{
padding: 7px 5px 0 7px;
font-size: 14px;
line-height: 13px;
font-weight: bold;
}
p{
margin: 0 0 10px;
}
.selector .selector-filter{
width: 100%;
}
.input-group{
position: relative;
display: table;
border-collapse: separate;
}
.selector select[multiple=multiple]{
border-left: 0;
border-top: 1px solid #d0d0d0;
border-bottom: 1px solid #d0d0d0;
margin: 0;
padding-left: 3px;
width: 100%;
height: 200px;
display: block;
max-width: none !important;
}
a.selector-chooseall,a.selector-clearall{
border-top: 1px solid #e4e4e4;
display: block;
margin: 0;
padding: 2px 7px;
font-size: 11px;
line-height: 20px;
font-weight: bold;
}
.selector ul.selector-chooser{
float: left;
margin: 100px 2px 0;
padding: 0;
width: 31px;
list-style: none;
}
.selector ul.selector-chooser li{
margin-top: 10px;
}
.selector .selector-chosen select[multiple=multiple]{
height: 230px;
}
</style>
这个时候再去刷新网页,我们可以看到模板以及变成我们想要的了
三、导入公司列表
接下来就是怎么把我们要全选的公司列表导入到可用项,那就要用到js了,我们可以在页面上看到公司列表是位于select多选框中的
首先,在后台写好返回所有公司的接口,在模板中添加js
//从后台请求到公司,添加到页面的select中
$(document).ready(function () {
$.getJSON('接口',function (data) {
if(data.status == 0){
for(var i=0;i<data.data.length;i++){
var dzobj = data.data[i];
$('#id_company_form').append("<option value='"+dzobj.公司id+"'>"+dzobj.公司名称+"</option>");
}
}
})
});
刷新页面,我们可以看到公司已经出来了,接着就是添加单击添加、选择全部、删除全部、搜索几个功能的js了,我就直接把js贴在这里了
// 添加公司
$('#id_company_form').dblclick(function () {
$('#id_company_form option').each(function () {
if(this.selected == true){
$('#id_com_list').append(this);
}
});
if($('#id_company_form option').length == 0){
$('.selector-chooseall').addClass('disabled')
}else {
$('.selector-chooseall').removeClass('disabled')
}
if($('#id_com_list option').length == 0){
$('.selector-clearall').addClass('disabled')
}else {
$('.selector-clearall').removeClass('disabled')
}
});
//删除公司
$('#id_com_list').dblclick(function () {
$('#id_com_list option').each(function () {
if(this.selected == true){
$('#id_company_form').append(this);
}
});
if($('#id_company_form option').length == 0){
$('.selector-chooseall').addClass('disabled')
}else {
$('.selector-chooseall').removeClass('disabled')
}
if($('#id_com_list option').length == 0){
$('.selector-clearall').addClass('disabled')
}else {
$('.selector-clearall').removeClass('disabled')
}
});
//全选添加
$('.selector-chooseall').click(function () {
$('#id_company_form option').each(function () {
$('#id_com_list').append(this);
});
//将所有公司设置为选中状态
var opts = document.getElementById("id_com_list").options;
for (var i = 0; i < opts.length; i++){
opts[i].selected = true;
}
$('.selector-chooseall').addClass('disabled');
$('.selector-clearall').removeClass('disabled')
});
//全选删除
$('.selector-clearall').click(function () {
$('#id_com_list option').each(function () {
$('#id_company_form').append(this);
});
$('.selector-clearall').addClass('disabled');
$('.selector-chooseall').removeClass('disabled')
});
//搜索框搜索公司
var inputBtn = document.getElementById("id_company_input");
var opts = document.getElementById("id_company_form").options;
inputBtn.onkeyup = search;
function search() {
var inputCont = inputBtn.value; //string
for (var i = 0; i < opts.length; i++) {
var optCont = opts[i].innerHTML; //string
var macthStr = optCont.match(inputCont);
if (inputCont != 0) { //为什么加这个判断呢?不加的话,按Tab键(但是用鼠标点击则不会显示),输入框就算没有输入内容,隐藏的opt标签也会显示
if (macthStr) {
opts[i].style.display = "block";
} else {
opts[i].style.display = "none";
}
}else {
opts[i].style.display = "block";
}
}
}
四、在后台adminx中保存添加的数据
在该页面对应的类中,重写保存方法
from xadmin.views.base import filter_hook
class XXXAdmin(object):
list_display = ['']
add_form_template = 'xxx.html'
@filter_hook
def save_models(self):
req_data = dict(self.request.POST)
com_list = req_data.get('com_list') # 取到选择的公司列表
update_sql = req_data.get('update_sql') # 取到要对这些公司操作/对应的内容
if com_list and update_sql:
保存到你要保存表中