项目一:CRM(客户关系管理系统)--6-编辑页面、动态modelform、双向复选框

功能是永远加不完的!重头戏的Action放在后面作为压轴,接下来该添加三级页面啦!

1. 添加编辑页面轮廓

有的朋友可能会问:为何直接写编辑页面而没有写添加页面?那是因为二者是相互继承的关系,个人觉得先写编辑比较好,然后添加继承编辑页面,改动基本上后台数据的更新与存储的问题。

1.1. 原生admin路由分析

如图:

 

1.2. 构建编辑页面路由

king_admin应用下的urls.py文件中添加:

1 from django.conf.urls import url
2 from king_admin import views
3 urlpatterns = [
4     url(r'^$', views.index, name='table_index'),
5     url(r'^(\w+)/(\w+)/$', views.display_objects, name='display_objects'),
6     url(r'^(\w+)/(\w+)/(\d+)/edit/$', views.table_object_edit,name="table_object_edit"),  #添加该行数据
7 ]

 

1.3. 添加视图函数

king_admin应用下的views.py文件中添加:

1 def table_object_edit(request, app_name, table_name, object_id):
2     return render(request, 'king_admin/table_object_edit.html')

 

1.4. 添加模板文件

template/king_admin/目录下的table_object_edit.html文件,并在文件中添加如下内容:

1 {%  extends 'king_admin/table_index.html' %}
2 {% block extra-css-resources %}
3      
4 {% endblock %}
5 {% block container %}
6      
7 {% endblock %}

 

1.5.添加编辑页面的入口

上面我们已经写完基本的页面流程,现在来添加编辑页面入口来打通整体流程,二级显示页面我们通过在templates中进行编写,修改这里即可,只需要添加一个参数(request),索引值和判断:

 1 ...
 2  
 3 <-----------------------创建表格行数据-----------------------------
 4 @register.simple_tag
 5 def create_row(request, query_set_obj, admin_class):
 6     #创建标签元素--空,None不行
 7     element = ''
 8  
 9     #遍历要显示的models字段
10     for number, row in enumerate(admin_class.list_display):
11     #获取显示字段对应的字段对象
12         field_obj = admin_class.model._meta.get_field(row)
13     #获取数据
14         #判断choice
15         if field_obj.choices:
16             #通过反射获取对象里面的值,并执行该方法get_字段_display()获取choices里面的数值
17             row_data = getattr(query_set_obj, 'get_{0}_display'.format(row))()
18         else:
19             row_data = getattr(query_set_obj, row)
20  
21         #时间格式转换
22         if type(row_data).__name__ == 'datetime':
23             row_data = row_data.strftime('%Y-%m-%d %H-%M-%S')
24  
25         #添加编辑页面入口
26         if number == 0: #add a tag, 可以跳转到修改页
27             row_data = "<a href='{request_path}{obj_id}/edit/'>{data}</a>".format(request_path=request.path,
28                                                                                         obj_id=query_set_obj.id,
29                                                                                         data=row_data)
30  
31         #标签元素的拼接
32         element += "<td>{0}</td>".format(row_data)
33     return mark_safe(element)
34  
35 ...

上述内容改完后,不要忘记在模板文件中还要添加一个参数:request

访问看看:

 

2. 填充编辑页面详情

2.1. 编写动态生成ModelForm派生类的功能函数

由于数据量很大,每条数据都要进入到第三级页面中,生成新的页面进行操作:添加、修改、删除等。那么,我是不是要针对每条数据都要写一套代码,很显然是不可能的!作为程序员,重复代码就是最大的BUG,尤其是大量的同样代码。

在三级页面中,不论是编辑、添加还是删除都有共通的地方。那么该怎么实现呢?好在Django为我们提供了便捷的方式:动态生成Form表单。

Django中,原生的admin常结合models使用的Form表单功能是ModelForm,它能够配合数据库动态生成数据表单。

我们知道如何动态的实现表单功能了,那它同样的问题就是代码的重复问题,那么多的数据,我们要写那么多的ModelForm吗?回答是肯定的:不可能! 不想写重复代码其实也很简单的,我们只需要动态生成ModelForm不就行了嘛!

通常我们使用ModelForm会这样:

1 from django.forms import ModelForm
2 from crm import models
3 #要动态生成的目标类
4 class CustomerModelForm(ModelForm):
5     class Meta:
6         model =  models.Customer
7         fields = "__all__"

现在,我们要让它自动创建:在king_admin项目的目录下,创建forms.py文件。

 1 from django.forms import ModelForm
 2  
 3 def create_model_form(request,admin_class):
 4     '''
 5     动态生成ModelForm类
 6     :param request:
 7     :param admin_class:
 8     :return:
 9     '''
10     <-----------------------类成员构造-----------------------------
11     class Meta:
12         model = admin_class.model
13         fields = "__all__"
14     #类的成员
15     attrs = {'Meta':Meta}
16  
17     <-----------------------动态创建类-----------------------------
18     #type函数创建类--->type('类名',(基类,),以字典形式的类的成员)
19     _model_form_class =  type("DynamicModelForm",(ModelForm,),attrs)
20  
21     <-----------------定义创建对象的方法-----------------------------
22     # 定义__new__方法,用于创建类,cls类名
23     def __new__(cls, *args, **kwargs):
24         # 遍历数据库的所有字段和字段对应的对象
25         for field_name, field_obj in cls.base_fields.items():
26             # 为字段对象的组件添加class属性
27             field_obj.widget.attrs['class'] = 'form-control'
28         # 创建当前类的实例--->即创建子类
29         return ModelForm.__new__(cls)
30         # 定义元数据
31  
32     <-------------------为对象添加属性--------------------------------
33     #为该类添加__new__静态方法,当调用该类时,会先执行__new__方法,创建对象
34     # 这里会覆盖父类的__new__
35     setattr(_model_form_class,'__new__',__new__)
36  
37     return _model_form_class

 

2.2 编写视图函数

在二级显示页面中,我们通过点击id值跳转到编辑页面,然后经过路由触发视图函数获取到相关数据,修改会经过上面创建的表单验证类进行验证:

 1 ...
 2 from king_admin.forms import create_model_form
 3  
 4 ...
 5 def table_object_edit(request, app_name, table_name, object_id):
 6     admin_class = site.enabled_admins[app_name][table_name]
 7     #创建ModelForm类
 8     model_form = create_model_form(request, admin_class)
 9     #通过id获取数据库内容
10     object_list = admin_class.model.objects.get(id=object_id)
11  
12     if request.method == 'POST':
13         #表单进行验证,更新数据
14         form_object = model_form(request.POST, instance=object_list)
15         if form_object.is_valid():
16             form_object.save()
17     else:
18         form_object = model_form(instance=object_list)
19  
20     return render(request, 'king_admin/table_object_edit.html', {"form_object": form_object,
21                                                                  "admin_class": admin_class,
22                                                                  "app_name": app_name,
23                                                                  "table_name": table_name})

2.3 编写模板文件

在新建的table_object_edit.html中我们添加的应该会比较多,因此,会拆分成几大部分编写。

2.3.1 基础字段内容显示

先将数据内容显示和字段名称显示出来:

 1 {%  extends 'king_admin/table_index.html' %}
 2  
 3 {% block extra-css-resources %}
 4  
 5 {% endblock %}
 6  
 7  
 8 {% block container %}
 9     <form method="post" class="form-horizontal">
10     {% csrf_token %}
11         {% for field in form_object %}
12         <div class="form-group" >
13             {# 显示名称 #}
14             <label  class="col-sm-3 control-label" style="font-weight: normal">
15                     {{ field.label }}
16             </label>
17             {# 显示数据输入框 #}
18             <div class="col-lg-6" style="width: auto">
19                 {{ field }}
20             </div>
21       </div>
22         {% endfor %}
23     </form>
24 {% endblock %}

效果如下:

 

2.3.2 必填字段显示设置

效果我们看到了,已经达到预期。在回过头看看form_object到底是什么?

在视图函数中,我们通过打印form_object(自行添加print(form_object))能够看到如下内容:

 1 <tr><th><label for="id_name">Name:</label></th><td><input class="form-control" id="id_name" maxlength="32" name="name" type="text" value="dfgh" /></td></tr>
 2 <tr><th><label for="id_qq">Qq:</label></th><td><input class="form-control" id="id_qq" maxlength="64" name="qq" type="text" value="0002" required /></td></tr>
 3 <tr><th><label for="id_qq_name">Qq name:</label></th><td><input class="form-control" id="id_qq_name" maxlength="64" name="qq_name" type="text" value="发电规划" /></td></tr>
 4 <tr><th><label for="id_phone">Phone:</label></th><td><input class="form-control" id="id_phone" maxlength="64" name="phone" type="text" value="234蚊346" /></td></tr>
 5 <tr><th><label for="id_source">Source:</label></th><td><select class="form-control" id="id_source" name="source" required>
 6 <option value="">---------</option>
 7 <option value="0" selected="selected">转介绍</option>
 8 <option value="1">QQ群</option>
 9 <option value="2">官网</option>
10 <option value="3">百度推广</option>
11 <option value="4">51CTO</option>
12 <option value="5">知乎</option>
13 <option value="6">市场推广</option>
14 </select></td></tr>
15 <tr><th><label for="id_referral_from">转介绍人qq:</label></th><td><input class="form-control" id="id_referral_from" maxlength="64" name="referral_from" type="text" value="567456" /></td></tr>
16 <tr><th><label for="id_consult_course">咨询课程:</label></th><td><select class="form-control" id="id_consult_course" name="consult_course" required>
17 <option value="">---------</option>
18 <option value="4">成功学</option>
19 <option value="5">搜索引擎</option>
20 <option value="6" selected="selected">内核开发</option>
21 <option value="7">相亲</option>
22 </select></td></tr>
23 <tr><th><label for="id_content">咨询详情:</label></th><td><textarea class="form-control" cols="40" id="id_content" name="content" rows="10" required>
24 如图</textarea></td></tr>
25 <tr><th><label for="id_tags">Tags:</label></th><td><select multiple="multiple" class="form-control" id="id_tags" name="tags">
26 <option value="3" selected="selected">大牛</option>
27 </select></td></tr>
28 <tr><th><label for="id_status">Status:</label></th><td><select class="form-control" id="id_status" name="status" required>
29 <option value="0">已报名</option>
30 <option value="1" selected="selected">未报名</option>
31 </select></td></tr>
32 <tr><th><label for="id_consultant">Consultant:</label></th><td><select class="form-control" id="id_consultant" name="consultant" required>
33 <option value="">---------</option>
34 <option value="1" selected="selected">三弗</option>
35 </select></td></tr>
36 <tr><th><label for="id_memo">Memo:</label></th><td><textarea class="form-control" cols="40" id="id_memo" name="memo" rows="10">
37 如图用户</textarea></td></tr>

细心的朋友会发现一个required,也会问这是什么鬼?哪来的?其实回头看看打印内容目的就是要看这个required属性。

在独立使用Form表单时,我们可以独立设置相关字段的参数,同样在MoldelForm中也是可以的,但是有一点是值得注意的: If the model field has blank=True, then required is set to False on the form field. Otherwise, required=True.这是官方的原话。意思是:如果在model中字段参数中设置了blank=True,那么Form中的required=False;若没设置blank=True,则默认为required=True(具体看源码的初始化函数设定)。

参考:Django官方文档和源码

现在,明白了required是怎么来的了吧!好了,开始该处理它了,只需要我们在模板文件中添加一个简单的判断和样式修饰:

 1 {# 显示名称 #}
 2 {% if field.field.required %}
 3     <label  class="col-sm-3 control-label" style="font-weight: normal">
 4             <span style="color: red">*</span>{{ field.label }}
 5     </label>
 6 {% else %}
 7     <label  class="col-sm-3 control-label" style="font-weight: normal">
 8         {{ field.label }}
 9 </label>
10 {% endif %}   

渲染后的效果:

 

2.3.3 添加保存按钮

基本的显示字段和样式添加的差不多了,接下来就是添加提交的按钮(保存)。在同一个form表单中添加如下:

 1 ...
 2  
 3                 {# 显示数据输入框 #}
 4                 <div class="col-lg-6" style="width: auto">
 5                     {{ field }}
 6                 </div>
 7             </div>
 8         {% endfor %}
 9     {# 添加保存按钮 #}
10      <div class="form-group">
11           <div class="col-sm-10 ">
12             <button type="submit" class="btn btn-success pull-right">保存</button>
13           </div>
14       </div>

渲染效果:

 

2.3.4 编辑测试

 

修改表格中一些内容:

 

保存后到上级页面中查看是否已经更改:

已经修改成功!

这里需要注意的是,前端展示数据的变化情况,由几个因素决定:1.检索。2.搜索。3.页码。4.排序...。这里只是做了页码的参数传递,如果修改前前端展示的是基于检索、搜索、页码等组合选出的数据,你在修改完后,其它过滤字段就丢失了,就不能返回修改前那条数据所在的页码。就如图上图展示的,排序字段丢失了,编辑后跳转回来的页面数据就不是id=4的数据了。

修改完成后的效果应该是这样:

 

2.3.5 完善保存按钮,添加跳转

保存的功能已经实现,但是有一点还是比较苦逼的:保存后,没有自动跳转到上一页。那就给它添加一个跳转链接,但是为了用户体验良好,还要考虑一个问题:考虑到分页,返回后直接到用户点击时的页面。这里你有没有想起之前我们所做的过滤、排序功能啥的都是基于分页来的, 同样我们在这里基于分页来做。

在入口处,我们添加的是一个<a></a>标签,并在里面添加了动态参数拼接成url,这是因为这样,通过这个url来传递当前页码的参数:***/**/?get_page=get_page

1. 修改table_objs.html文件中的内容,只需要为下面标签添加一个get_page参数:

1 {#创建列表行数据#}
2 {% create_row request item admin_class get_page %}

2. 修改该标签对应的templatetags中对应的标签函数,只需要添加形参和修改<a>标签

 1 <-----------------------创建表格行数据-----------------------------
 2 @register.simple_tag
 3 def create_row(request, query_set_obj, admin_class, get_page):
 4     #创建标签元素--空,None不行
 5     element = ''
 6  
 7     #遍历要显示的models字段
 8     for number, row in enumerate(admin_class.list_display):
 9     #获取显示字段对应的字段对象
10         field_obj = admin_class.model._meta.get_field(row)
11     #获取数据
12         #判断choice
13         if field_obj.choices:
14             #通过反射获取对象里面的值,并执行该方法get_字段_display()获取choices里面的数值
15             row_data = getattr(query_set_obj, 'get_{0}_display'.format(row))()
16         else:
17             row_data = getattr(query_set_obj, row)
18  
19         #时间格式转换
20         if type(row_data).__name__ == 'datetime':
21             row_data = row_data.strftime('%Y-%m-%d %H-%M-%S')
22  
23         #添加编辑页面入口
24         if number == 0: #add a tag, 可以跳转到修改页
25             row_data = "<a href='{request_path}{obj_id}/edit/?get_page={get_page}'>{data}</a>".format(request_path=request.path,
26                                                                                         obj_id=query_set_obj.id,
27                                                                                         get_page=get_page,
28                                                                                         data=row_data)
29  
30         #标签元素的拼接
31         element += "<td>{0}</td>".format(row_data)
32     return mark_safe(element)

3.视图函数kingadmin/views.py增加如下代码

 1 def table_object_edit(request, app_name, table_name, object_id):
 2     """
 3     编辑表中的一条数据
 4     :param request:
 5     :param app_name:
 6     :param table_name:
 7     :param id:
 8     :return:
 9     """
10     admin_class = kingadmin.enabled_admins[app_name][table_name]
11 
12     model_form = create_model_form(request, admin_class)
13 
14     object_list = admin_class.model.objects.get(id=object_id)
15     page = request.GET.get('page')
16     if request.method == 'POST':
17         form_object = model_form(request.POST, instance=object_list)
18         if form_object.is_valid():
19             form_object.save()
20             return redirect('/kingadmin/{0}/{1}?page={2}'.format(
21                 app_name,
22                 table_name,
23                 page,
24             ))
25         else:                  # 目前可以删除(无论检验成功与否都是要返回table_object_edit.html)
26             return render(request, 'kingadmin/table_object_edit.html', {'form_object': form_object,
27                                                                         'admin_class': admin_class,
28                                                                         'app_name': app_name,
29                                                                         'table_name': table_name,
30                                                                         })              # 目前可以删除
31     else:
32         form_object = model_form(instance=object_list)
33     return render(request, 'kingadmin/table_object_edit.html', {'form_object': form_object,
34                                                                 'admin_class': admin_class,
35                                                                 'app_name': app_name,
36                                                                 'table_name': table_name,
37                                                                 })

同时,在模板文件中table_object_edit.html中,需要添加错误提示:

 1 {% extends 'project/head.html' %}
 2 {% load tags %}
 3 
 4 {% block extra_css_resource %}
 5 
 6 {% endblock %}
 7 
 8 {% block main %}
 9     <form class="form-horizontal" method="POST">
10         {% csrf_token %}
11         {% for field in form_object %}
12             <div class="form-group">
13                 {#                <label for="inputEmail3" class="col-sm-2 control-label">Email</label>#}
14                 {% if field.field.required %}
15                     <label class="col-sm-3 control-label" style="font-weight:bold"><span
16                             style="color:red;">*</span>{{ field.label }}</label>
17                 {% else %}
18                     <label class="col-sm-3 control-label" style="font-weight:normal;">{{ field.label }}</label>
19                 {% endif %}
20                 <div class="col-sm-6">
21                     {{ field }}<span style="color:red;">{{ field.errors }}</span>
22                 </div>
23             </div>
24         {% endfor %}
25         <div class="form-group">
26             <div class="col-sm-10">
27                 <button type="submit" class="btn btn-success pull-right">保存</button>
28             </div>
29         </div>
30     </form>
31 {% endblock %}

渲染测试:

2.4 双向复选框

为何要在最后来改这个复选框?因为咱们这个在添加或其他页面也会出现,甚至是继承下面即将编写的双向复选框。

2.4.1 原生admin的双向复选框

先来看看原生admin的双向复选框:

需要在admin.py文件中的自定义类中添加字段:filter_horizontal = ('tags',)

做的非常的不错。 

原生版的效果图如下:

 我们目前的前端展示的效果如下:

 

相距甚远,我们下面就主要实现这个效果。

 

2.4.2 添加双向复选框

跟上面的方式一样,我们要在之前自己编写的注册那里添加类似的字段:

1 king_admin.py中需要现实的类中添加:filter_horizontal = ['tags']
2 King_admin_base.py中的ModelAdmin中添加:filter_horizontal = ['tags'] 

基本的配置操作就搞定了!

接下来就是实现功能的阶段:

1. 判断配置中是否存在设置的字段

1 在table_object_edit.html中,我们已经显示出tags复选框,在这里要额外的加一个简单的判断,
这里作为演示简单的添加一个双击的事件,作为选择方式。比较不错的推荐开源的多重复选框。

 

需要添加的标签如下:

  1 {% load tags %}
  2 {% block extra-css-resources %}
  3 <style type="text/css">
  4     .selector{
  5         float: left;
  6         text-align: left;
  7     }
  8     h5{
  9         border: 1px solid #ccc;
 10         border-radius: 4px 4px 0 0;
 11         background: #f8f8f8;
 12         color: #666;
 13         padding: 8px;
 14         font-weight: 400;
 15         font-size: 13px;
 16         height: 30px;
 17         width: 300px;
 18         margin-left: 15px;
 19         margin-bottom: 0;
 20     }
 21      .right,.left{
 22          border: 1px solid #ccc;
 23          border-top: 0;
 24          margin-left: 15px;
 25     }
 26      ul{
 27          -webkit-padding-start: 30px;
 28      }
 29     .selector-add{
 30         background: url(/static/imgs/selector-icons.svg) 0 -96px no-repeat;
 31         list-style: none;
 32     }
 33     .selector-remove{
 34         background: url(/static/imgs/selector-icons.svg) 0 -64px no-repeat;
 35     }
 36 .selector-add, .selector-remove{
 37         width: 16px;
 38         height: 16px;
 39         display: block;
 40         text-indent: -3000px;
 41         overflow: hidden;
 42         cursor: default;
 43         opacity: 0.3;
 44 }
 45 .selector-chooser {
 46     float: left;
 47     width: 16px;
 48     background-color: #eee;
 49     border-radius: 10px;
 50     margin: 70px 5px 0 20px;
 51     padding: 0;
 52 }
 53 </style>
 54 {% endblock %}
 55 ...
 56  
 57 <form method="post" class="form-horizontal" οnsubmit="return SelectAllChosenData()">
 58     {% csrf_token %}
 59  
 60     ...
 61  
 62                 {# 双向复选框的判断 #}
 63                 {% if field.name in admin_class.filter_horizontal %}
 64                     {# 左复选框 #}
 65                     <div class="selector ">
 66                         <h5>Available tags</h5>
 67                         <div  class="selector">
 68                             {# 获取多对多的被选中数据 #}
 69                             {% m2m_get_object_list admin_class form_object field  as select_object_list %}
 70                                 <select class="left" style="width: 300px;height: 200px" multiple name="{{ field.name }}" id="id_{{ field.name }}_from">
 71                                     {% for item in select_object_list %}
 72                                         <option οndblclick="MoveElementTo(this,'id_{{ field.name }}_to','id_{{ field.name }}_from')" value="{{ item.id }}">{{ item }}</option>
 73                                     {% endfor %}
 74                                 </select>
 75                         </div>
 76                     </div>
 77                     {# 中间箭头 #}
 78                     <div style="float: left;margin-top: 50px">
 79                     <ul class="selector-chooser">
 80                         <li><a title="Choose" href="#" id="id_tags_add_link" class="selector-add">Choose</a></li>
 81                         <li><a title="Remove" href="#" id="id_tags_remove_link" class="selector-remove">Remove</a></li></ul>
 82                     </div>
 83                     {# 右复选框 #}
 84                     <div class="selector ">
 85                         <h5 style="background-color: #79aec8; color:white">Choosen tags</h5>
 86                         <div  class="selector">
 87                             {% get_selected_object_list form_object field as get_selected_list %}
 88                             <select class="right" style="width: 300px;height: 200px" multiple  id="id_{{ field.name }}_to" name="{{ field.name }}">
 89                                 {% for item in get_selected_list %}
 90                                     <option οndblclick="MoveElementTo(this,'id_{{ field.name }}_from','id_{{ field.name }}_to')" value="{{ item.id }}">{{ item }}</option>
 91                                 {% endfor %}
 92                             </select>
 93                         </div>
 94                     </div>
 95  
 96                 {% else %}
 97                     <div class="col-lg-6" style="width: auto">
 98                         {{ field }}<span style="color: red">{{ field.errors.as_text }}</span>
 99                     </div>
100                 {% endif %}
101 ...
102  
103 <script>
104          function MoveElementTo(self,target_id,source_id) {
105             var opt_ele = "<option value='" + $(self).val() + "' οndblclick=MoveElementTo(this,'" + source_id +"','"+ target_id +"')>" + $(self).text() + "</option>";
106             $("#" +target_id).append(opt_ele);
107             $(self).remove();
108  
109     }
110         //提交所有数据
111         function SelectAllChosenData() {
112  
113         $("select[class='right'] option").each(function () {
114             $(this).prop("selected",true);
115         });
116         return true;
117     }
118     </script>
119 ...

上述代码实现的基本的复选功能,tags.py需要添加两个函数,一个用于返回所有对应manytomany字段的所有数据,另外一个是将该条记录对应的manytomany字段的数据查询出来,如下:

  1 from django import template
  2 from django.utils.safestring import mark_safe
  3 from kingadmin.utils import filters_to_text
  4 
  5 register = template.Library()
  6 
  7 
  8 @register.simple_tag
  9 def table_verbose_name(admin_class):
 10     return admin_class.model._meta.verbose_name
 11 
 12 
 13 @register.simple_tag
 14 def create_page_num(contacts, ordering, _q, filter_text):
 15     """
 16     返回分页按钮的html方式
 17     :param contacts: Paginator.page(num)
 18     :return:
 19     """
 20     page_num_html = ''
 21     dot_sign = False
 22     for number in contacts.paginator.page_range:
 23         btn_element = """<li class="{0}"><a href="?page={1}&o={2}&_q={3}&{4}">{5}</a></li>"""
 24         li_class = ''
 25         if number < 3 \
 26                 or number > contacts.paginator.num_pages - 2 \
 27                 or abs(number - contacts.number) <= 2:  # 前三页,后2页,当前页的前后2页
 28             if number == contacts.number:  # 页码等于当前页
 29                 li_class = "active"
 30             dot_sign = False
 31             page_num_html += btn_element.format(li_class, number, ordering, _q, filter_text, number)
 32         else:
 33             if not dot_sign:
 34                 page_num_html += '<li><a>...</a></li>'
 35                 dot_sign = True
 36     return mark_safe(page_num_html)
 37     # for number in contacts.paginator.page_range:
 38     #     if number < 3 or number > contacts.paginator.num_pages - 2 or abs(contacts.number - number) <= 2:      # 前两页或最后两页 #}
 39     #         if number == contacts.number:
 40     #             page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number, number)
 41     #             dot_sign = False
 42     #         else:
 43     #             dot_sign = False
 44     #             page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number)
 45     #     elif contacts.paginator.num_pages < 7:      # 总页数为6,直接显示页码
 46     #         dot_sign = False
 47     #         page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number)
 48     #     elif contacts.paginator.num_pages >= 7:      # 7页以上
 49     #         temp = contacts.paginator.num_pages / 2
 50     #         if type(temp) is int:     # 能整除,偶数页,显示中间四页
 51     #             if temp - 1 <= number <= temp + 2:     # 中间四页
 52     #                 if number == contacts.number:       # 判断当前页
 53     #                     page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number,
 54     #                                                                                                        number)
 55     #                     dot_sign = False
 56     #                 else:
 57     #                     dot_sign = False
 58     #                     page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number)
 59     #             else:                               # 非中间四页
 60     #                 page_num_html += """<li><a href="#">...</a></li>"""
 61     #         else:                   # 不能整除,奇数页,显示中间三页
 62     #             if int(temp) <= number <= temp + 2:   # 中间三页
 63     #                 if number == contacts.number:
 64     #                     page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number,
 65     #                                                                                                        number)
 66     #                     dot_sign = False
 67     #                 else:
 68     #                     dot_sign = False
 69     #                     page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number)
 70     #             else:                               # 非中间三页
 71     #                 if not dot_sign:
 72     #                     page_num_html += """<li><a href="#">...</a></li>"""
 73     #                     dot_sign = True
 74     # return mark_safe(page_num_html)
 75 
 76 
 77 @register.simple_tag
 78 def field_verbose_name(filter_condition, admin_class, filter_conditions_customer):
 79     """
 80     返回表中的字段的verbose_name,取代英文
 81     :param filter_condition: string
 82     :param admin_class: class
 83     :return:
 84     """
 85     if hasattr(admin_class.model, filter_condition):
 86         field_class = admin_class.model._meta.get_field(filter_condition)
 87         name = field_class.verbose_name
 88         choices = field_class.choices
 89         selected_value = ''
 90         label_html = """<label for={0}>{1}</label>""".format(field_class.name, name)  # label content
 91         select_html = """<select class="form-control" id="{0}" name="{1}">""".format(field_class.name, field_class.name)
 92         # '<option>1</option></select>'                                 # select content
 93 
 94         # selected
 95         if field_class.name in filter_conditions_customer:
 96             selected_value = filter_conditions_customer[field_class.name]
 97 
 98         if choices or type(field_class).__name__ == 'ForeignKey':  # 外键
 99             for item in field_class.get_choices():
100                 if str(item[0]) == selected_value:
101                     select_html += """<option value={0} selected>{1}</option>""".format(item[0], item[1])
102                 else:
103                     select_html += """<option value={0}>{1}</option>""".format(item[0], item[1])
104         select_html += '</select>'
105         group_html = label_html + select_html
106 
107         return mark_safe(group_html)
108     else:
109         return 'there is no %s' % filter_condition
110 
111 
112 @register.simple_tag
113 def ret_field_value(request, query_set, fields_name, page, order, filter_conditions_customer, search_text):
114     """返回admin_class中list_display包含字段对应的一行数据,并组装成html格式"""
115     row_data = ''
116     filter_text = filters_to_text(filter_conditions_customer)
117     for k, field_name in enumerate(fields_name):
118         # options的数据类型如下:
119         # ((0, '转介绍'),
120         #  (1, 'QQ群'),
121         #  (2, '官网'),
122         #  (3, '百度推广'),
123         #  (4, '51CTO'),
124         #  (5, '知乎'),
125         #  (6, '市场部推广'))
126         # """<th><span><input type="checkbox"></span></th>"""
127         options = query_set._meta.get_field(field_name).choices
128         option_value = getattr(query_set, field_name)
129         if options:  # 处理多选字段,即choices属性不为空
130             option_means = [item for item in options if item[0] == option_value][0][1]
131             unit_data = '<td>{0}</td>'.format(option_means)
132         elif type(option_value).__name__ == 'datetime':  # 处理时间格式
133             option_value = option_value.strftime("%Y-%m-%d %H:%M:%S")
134             unit_data = '<td>{0}</td>'.format(option_value)
135         elif k == 0:
136             unit_data = '<td><a href="{0}/{1}/edit?page={2}&o={3}&_q={4}&{5}">{6}</a></td>'.format(
137                 request.path,
138                 query_set.id,
139                 page,
140                 order,
141                 search_text,
142                 filter_text,
143                 option_value,
144             )
145         else:
146             unit_data = '<td>{0}</td>'.format(option_value)
147         row_data += unit_data
148     row_data = '<tr><td><span><input type="checkbox" tag="object_checkbox" value="{0}"></span></td>{1}</tr>'.format(
149         query_set.id,
150         row_data
151     )
152     return mark_safe(row_data)
153 
154 
155 @register.simple_tag
156 def ret_getattr(query_set, field_name):
157     return hasattr(query_set, field_name)
158 
159 
160 @register.simple_tag
161 def create_row(query_set_obj, admin_class):
162     element = ''
163     for row in admin_class.list_display:
164 
165         field_obj = admin_class.model._meta.get_field(row)
166         if field_obj.choices:
167             row_data = getattr(query_set_obj, 'get_{0}_display'.format(row))()
168         else:
169             row_data = getattr(query_set_obj, row)
170         if type(row_data).__name__ == 'datetime':
171             row_data = row_data.strftime('%Y-%m-%d %H:%M:%S')
172 
173         element += "<td>{0}</td>".format(row_data)
174     return mark_safe(element)
175 
176 
177 @register.simple_tag
178 def create_page_element(page, filter_conditions):
179     page_btns = ''
180     filters = ''
181     for k, v in filter_conditions.items():
182         filters += '&{0}={1}'.format(k, v)
183     add_dot_ele = False  # 标志符
184     for page_num in page.paginator.page_range:  # query_set.paginator.page_range: range(1,n),分的总页数,
185         # page_num:每页的页码
186         # query_set.paginator.num_pages: 一共分了多少页
187         # query_set.number: 页对应的页码
188         if page_num < 3 or \
189                 page_num > page.paginator.num_pages - 2 or \
190                 abs(page.number - page_num) <= 2:  # 代表最前2页或最后2页 #abs判断前后1页
191             element_class = ""
192             if page.number == page_num:
193                 add_dot_ele = False
194                 element_class = "active"
195             page_btns += '''<li class="%s"><a href="?page=%s%s">%s</a></li>''' % (element_class,
196                                                                                   page_num,
197                                                                                   filters,
198                                                                                   page_num)
199         else:
200             if not add_dot_ele:
201                 page_btns += '<li><a href="#">...</a></li>'
202                 add_dot_ele = True
203 
204     return mark_safe(page_btns)
205 
206 
207 @register.simple_tag
208 def render_filter_element(condition, admin_class, filter_conditions):
209     '''
210 
211     :param condition: 字符串, list_filter中的一个
212     :param admin_class: 数据库中的数据表类
213     :param filter_conditions: 字典,key=list_filter中的一个, value=前端传回的对应的option的value值
214     :return:
215     '''
216     # 初始化下拉框
217     select_element = """<select class='form-control' name={0}><option value=''>------
218                                                                         </option>""".format(condition)
219     field_object = admin_class.model._meta.get_field(condition)  # 获取字段, admin_class中的字段
220     # 字段处理, 默认不选中
221     selected = ''  # choice处理
222     if field_object.choices:  # 遍历choices值
223         for choice_item in field_object.get_choices()[1:]:
224             # print(choice_item)
225             # 判断选择条件是否和choice值相等,
226             if filter_conditions.get(condition) == str(choice_item[0]):
227                 # 被选中
228                 selected = 'selected'
229             select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0],
230                                                                                 selected, choice_item[1])
231             selected = ''
232     # 外键处理
233     if type(field_object).__name__ == 'ForeignKey':
234         for choice_item in field_object.get_choices()[1:]:
235             # 判断选择条件是否和choice值相等
236             if filter_conditions.get(condition) == str(choice_item[0]):
237                 # 被选中
238                 selected = 'selected'
239             select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0],
240                                                                                 selected, choice_item[1])
241             selected = ''
242     select_element += '</select>'
243     return mark_safe(select_element)
244 
245 
246 @register.simple_tag
247 def ret_search_help(admin_class):
248     help_info = ''
249     if admin_class.search_fields:
250         # help_info += '搜索:'
251         for item in admin_class.search_fields:
252             help_info += item + ''
253     else:
254         help_info += '未定义搜索字段'
255 
256     return help_info
257 
258 
259 @register.simple_tag
260 def create_table_title(fields, order_after, filter_conditions_customer, search_text):
261     """
262 
263     :param fields:
264     :param order_after:
265     :param filter_conditions_customer:
266     :return:
267     """
268     # """<th><span><input type="checkbox"></span>"""
269     # """<a href="?o={{ field.name }} style="display:block;font-size:14px;">{{ field.verbose_name }}</a>"""
270     # 添加一列checkbox
271     ele_checkbox = """<th><span><input type="checkbox" id="test" οnclick="select_all_checkbox(this);"></span></th>"""
272     # filter_text
273     filter_text = ''
274     for k, v in filter_conditions_customer.items():
275         temp = k + '=' + v
276         filter_text += temp + '&'
277     filter_text = filter_text.rstrip('&')
278     # 添加title
279     ele_title = ''
280     # 设置标题的href
281     for field in fields:
282         temp = order_after.lstrip('-')
283         if temp == field.name:
284             ele_title += """<th><a href="?{0}&o={1}&_q={2}">{3}</a></th>""".format(
285                 filter_text,
286                 order_after,
287                 search_text,
288                 field.verbose_name
289             )
290         else:
291             ele_title += """<th><a href="?{0}&o={1}&_q={2}">{3}</a></th>""".format(
292                 filter_text,
293                 field.name,
294                 search_text,
295                 field.verbose_name
296             )
297     table_title = ele_checkbox + ele_title
298     return mark_safe(table_title)
299 
300 
301 @register.simple_tag
302 def get_horizontal_tag_values(field, admin_class, form_object):
303     field_obj = getattr(admin_class.model, field.name)
304     query_sets_all = field_obj.rel.to.objects.all()
305     # print('===>query_sets_all', query_sets_all)
306 
307     instance_field = getattr(form_object.instance, field.name)
308     query_sets_select = instance_field.all()
309     # print('====>query_sets_select', dir(query_sets_select.union()))
310 
311     diff_query_sets = query_sets_all.difference(query_sets_select)
312     # print('====>different_query_sets', diff_query_sets)
313     return diff_query_sets
314 
315 
316 @register.simple_tag
317 def get_horizontal_field_value(field, form_object):
318     print(form_object.instance.tags)
319     field_obj = getattr(form_object.instance, field.name)
320     selected_list = field_obj.all()
321     return selected_list

 

这是修改过后的内容,双方的内容转换了,就是表名已经成功。

2.5 添加返回按钮

这个就更简单了,但往往在数量少的时候我们会进行硬编码来写路径,要是动态生成该怎么搞呢?在这里,我们要引入DjangoURL逆向解析。 请看这里:Django路由。

table_object_edit.html文件中添加这一段代码:

 1 ...
 2 {% block container %}
 3     {# 添加下面的块,便于继续 #}
 4     {% block top %}
 5         <div class="panel-heading">
 6             <button  class="btn btn-success pull-right" ><a href="{% url 'king_admin:display_objects' app_name table_name %}" style="color: white">返回</a></button>
 7         </div>
 8     {% endblock %}
 9  
10     <form method="post" class="form-horizontal" οnsubmit="return SelectAllChosenData()">
11 ...

效果:

 

这里需要注意的是:

在前端展示页面table_object_edit.html中,客户类型的对应html标签中:

1 <select name="tags" class="form-control left" id="id_tags_from" multiple="multiple">
2 <option value="4" ondblclick="MoveElementTo(this, 'id_tags_to', 'id_tags_from')">
3 type4
4 </option>
5 <option value="5" ondblclick="MoveElementTo(this, 'id_tags_to', 'id_tags_from')">
6 type5
7 </option>
8 </select>

只有当option设置成selected属性时,点击保存的时候,数据才能保存到后台,不然的话是无法保存数据的,因此需要编写js脚本将所有class="form-control left"的所有option选项都设置selected属性:

 1 <script>
 2     function MoveElementTo(self, target_id, source_id) {
 3         var opt_ele = "<option value='" + $(self).val() + "' οndblclick=MoveElementTo(this,'" + source_id + "','" + target_id + "')>" + $(self).text() + "</option>";
 4         $('#' + target_id).append(opt_ele);
 5         $(self).remove();
 6     }
 7 
 8     function SelectAllChosenData() {
 9         $("select[class='form-control right'] option").each(function () {
10             $(this).prop('selected', true);
11             console.log('select write');
12         });
13         return true;
14     }
15 </script>
需要注意的是,jquery class选择器
$("select[class='form-control right'] option")
必须是class='form-control right'不能写成class='dright',不然找不到数据。

到此,编辑页面就算是基本完成了。

但是发现有一个bug:

经过排查发现前端渲染中没有处理多对多字段的数据:

因此增加处理多对多字段的功能:

  1 from django import template
  2 from django.utils.safestring import mark_safe
  3 from kingadmin.utils import filters_to_text
  4 
  5 register = template.Library()
  6 
  7 
  8 @register.simple_tag
  9 def table_verbose_name(admin_class):
 10     return admin_class.model._meta.verbose_name
 11 
 12 
 13 @register.simple_tag
 14 def create_page_num(contacts, ordering, _q, filter_text):
 15     """
 16     返回分页按钮的html方式
 17     :param contacts: Paginator.page(num)
 18     :return:
 19     """
 20     page_num_html = ''
 21     dot_sign = False
 22     for number in contacts.paginator.page_range:
 23         btn_element = """<li class="{0}"><a href="?page={1}&o={2}&_q={3}&{4}">{5}</a></li>"""
 24         li_class = ''
 25         if number < 3 \
 26                 or number > contacts.paginator.num_pages - 2 \
 27                 or abs(number - contacts.number) <= 2:  # 前三页,后2页,当前页的前后2页
 28             if number == contacts.number:  # 页码等于当前页
 29                 li_class = "active"
 30             dot_sign = False
 31             page_num_html += btn_element.format(li_class, number, ordering, _q, filter_text, number)
 32         else:
 33             if not dot_sign:
 34                 page_num_html += '<li><a>...</a></li>'
 35                 dot_sign = True
 36     return mark_safe(page_num_html)
 37     # for number in contacts.paginator.page_range:
 38     #     if number < 3 or number > contacts.paginator.num_pages - 2 or abs(contacts.number - number) <= 2:      # 前两页或最后两页 #}
 39     #         if number == contacts.number:
 40     #             page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number, number)
 41     #             dot_sign = False
 42     #         else:
 43     #             dot_sign = False
 44     #             page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number)
 45     #     elif contacts.paginator.num_pages < 7:      # 总页数为6,直接显示页码
 46     #         dot_sign = False
 47     #         page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number)
 48     #     elif contacts.paginator.num_pages >= 7:      # 7页以上
 49     #         temp = contacts.paginator.num_pages / 2
 50     #         if type(temp) is int:     # 能整除,偶数页,显示中间四页
 51     #             if temp - 1 <= number <= temp + 2:     # 中间四页
 52     #                 if number == contacts.number:       # 判断当前页
 53     #                     page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number,
 54     #                                                                                                        number)
 55     #                     dot_sign = False
 56     #                 else:
 57     #                     dot_sign = False
 58     #                     page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number)
 59     #             else:                               # 非中间四页
 60     #                 page_num_html += """<li><a href="#">...</a></li>"""
 61     #         else:                   # 不能整除,奇数页,显示中间三页
 62     #             if int(temp) <= number <= temp + 2:   # 中间三页
 63     #                 if number == contacts.number:
 64     #                     page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number,
 65     #                                                                                                        number)
 66     #                     dot_sign = False
 67     #                 else:
 68     #                     dot_sign = False
 69     #                     page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number)
 70     #             else:                               # 非中间三页
 71     #                 if not dot_sign:
 72     #                     page_num_html += """<li><a href="#">...</a></li>"""
 73     #                     dot_sign = True
 74     # return mark_safe(page_num_html)
 75 
 76 
 77 @register.simple_tag
 78 def field_verbose_name(filter_condition, admin_class, filter_conditions_customer):
 79     """
 80     返回表中的字段的verbose_name,取代英文
 81     :param filter_condition: string
 82     :param admin_class: class
 83     :return:
 84     """
 85     if hasattr(admin_class.model, filter_condition):
 86         field_class = admin_class.model._meta.get_field(filter_condition)
 87         name = field_class.verbose_name
 88         choices = field_class.choices
 89         selected_value = ''
 90         label_html = """<label for={0}>{1}</label>""".format(field_class.name, name)  # label content
 91         select_html = """<select class="form-control" id="{0}" name="{1}">""".format(field_class.name, field_class.name)
 92         # '<option>1</option></select>'                                 # select content
 93 
 94         # selected
 95         if field_class.name in filter_conditions_customer:
 96             selected_value = filter_conditions_customer[field_class.name]
 97 
 98         if choices or type(field_class).__name__ == 'ForeignKey':  # 外键
 99             for item in field_class.get_choices():
100                 if str(item[0]) == selected_value:
101                     select_html += """<option value={0} selected>{1}</option>""".format(item[0], item[1])
102                 else:
103                     select_html += """<option value={0}>{1}</option>""".format(item[0], item[1])
104         select_html += '</select>'
105         group_html = label_html + select_html
106 
107         return mark_safe(group_html)
108     else:
109         return 'there is no %s' % filter_condition
110 
111 
112 @register.simple_tag
113 def ret_field_value(request, query_set, fields_name, page, order, filter_conditions_customer, search_text):
114     """
115     返回admin_class中list_display包含字段对应的一行数据,并组装成html格式
116     :param request:
117     :param query_set: class instanceme
118     :param fields_name:
119     :param page:
120     :param order:
121     :param filter_conditions_customer:
122     :param search_text:
123     :return:
124     """
125     row_data = ''
126     filter_text = filters_to_text(filter_conditions_customer)
127     for k, field_name in enumerate(fields_name):
128         # options的数据类型如下:
129         # ((0, '转介绍'),
130         #  (1, 'QQ群'),
131         #  (2, '官网'),
132         #  (3, '百度推广'),
133         #  (4, '51CTO'),
134         #  (5, '知乎'),
135         #  (6, '市场部推广'))
136         # """<th><span><input type="checkbox"></span></th>"""
137         field_type = query_set._meta.get_field(field_name)
138         options = field_type.choices
139         option_value = getattr(query_set, field_name)
140         if options:  # 处理多选字段,即choices属性不为空
141             option_means = [item for item in options if item[0] == option_value][0][1]
142             unit_data = '<td>{0}</td>'.format(option_means)
143         elif type(option_value).__name__ == 'datetime':  # 处理时间格式
144             option_value = option_value.strftime("%Y-%m-%d %H:%M:%S")
145             unit_data = '<td>{0}</td>'.format(option_value)
146         elif k == 0:
147             unit_data = '<td><a href="{0}/{1}/edit?page={2}&o={3}&_q={4}&{5}">{6}</a></td>'.format(
148                 request.path,
149                 query_set.id,
150                 page,
151                 order,
152                 search_text,
153                 filter_text,
154                 option_value,
155             )
156         elif type(field_type).__name__ == 'ManyToManyField':        # 处理多对多字段
157             field_values = getattr(query_set, field_name).all()
158             temp = ''
159             for k, v in enumerate(field_values):
160                 temp += v.name + ','
161             temp = temp.rstrip(',')
162             unit_data = '<td>{0}</td>'.format(temp)
163         else:
164             unit_data = '<td>{0}</td>'.format(option_value)
165         row_data += unit_data
166     row_data = '<tr><td><span><input type="checkbox" tag="object_checkbox" value="{0}"></span></td>{1}</tr>'.format(
167         query_set.id,
168         row_data
169     )
170     return mark_safe(row_data)
171 
172 
173 @register.simple_tag
174 def ret_getattr(query_set, field_name):
175     return hasattr(query_set, field_name)
176 
177 
178 @register.simple_tag
179 def create_row(query_set_obj, admin_class):
180     element = ''
181     for row in admin_class.list_display:
182 
183         field_obj = admin_class.model._meta.get_field(row)
184         if field_obj.choices:
185             row_data = getattr(query_set_obj, 'get_{0}_display'.format(row))()
186         else:
187             row_data = getattr(query_set_obj, row)
188         if type(row_data).__name__ == 'datetime':
189             row_data = row_data.strftime('%Y-%m-%d %H:%M:%S')
190 
191         element += "<td>{0}</td>".format(row_data)
192     return mark_safe(element)
193 
194 
195 @register.simple_tag
196 def create_page_element(page, filter_conditions):
197     page_btns = ''
198     filters = ''
199     for k, v in filter_conditions.items():
200         filters += '&{0}={1}'.format(k, v)
201     add_dot_ele = False  # 标志符
202     for page_num in page.paginator.page_range:  # query_set.paginator.page_range: range(1,n),分的总页数,
203         # page_num:每页的页码
204         # query_set.paginator.num_pages: 一共分了多少页
205         # query_set.number: 页对应的页码
206         if page_num < 3 or \
207                 page_num > page.paginator.num_pages - 2 or \
208                 abs(page.number - page_num) <= 2:  # 代表最前2页或最后2页 #abs判断前后1页
209             element_class = ""
210             if page.number == page_num:
211                 add_dot_ele = False
212                 element_class = "active"
213             page_btns += '''<li class="%s"><a href="?page=%s%s">%s</a></li>''' % (element_class,
214                                                                                   page_num,
215                                                                                   filters,
216                                                                                   page_num)
217         else:
218             if not add_dot_ele:
219                 page_btns += '<li><a href="#">...</a></li>'
220                 add_dot_ele = True
221 
222     return mark_safe(page_btns)
223 
224 
225 @register.simple_tag
226 def render_filter_element(condition, admin_class, filter_conditions):
227     '''
228 
229     :param condition: 字符串, list_filter中的一个
230     :param admin_class: 数据库中的数据表类
231     :param filter_conditions: 字典,key=list_filter中的一个, value=前端传回的对应的option的value值
232     :return:
233     '''
234     # 初始化下拉框
235     select_element = """<select class='form-control' name={0}><option value=''>------
236                                                                         </option>""".format(condition)
237     field_object = admin_class.model._meta.get_field(condition)  # 获取字段, admin_class中的字段
238     # 字段处理, 默认不选中
239     selected = ''  # choice处理
240     if field_object.choices:  # 遍历choices值
241         for choice_item in field_object.get_choices()[1:]:
242             # print(choice_item)
243             # 判断选择条件是否和choice值相等,
244             if filter_conditions.get(condition) == str(choice_item[0]):
245                 # 被选中
246                 selected = 'selected'
247             select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0],
248                                                                                 selected, choice_item[1])
249             selected = ''
250     # 外键处理
251     if type(field_object).__name__ == 'ForeignKey':
252         for choice_item in field_object.get_choices()[1:]:
253             # 判断选择条件是否和choice值相等
254             if filter_conditions.get(condition) == str(choice_item[0]):
255                 # 被选中
256                 selected = 'selected'
257             select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0],
258                                                                                 selected, choice_item[1])
259             selected = ''
260     select_element += '</select>'
261     return mark_safe(select_element)
262 
263 
264 @register.simple_tag
265 def ret_search_help(admin_class):
266     help_info = ''
267     if admin_class.search_fields:
268         # help_info += '搜索:'
269         for item in admin_class.search_fields:
270             help_info += item + ''
271     else:
272         help_info += '未定义搜索字段'
273 
274     return help_info
275 
276 
277 @register.simple_tag
278 def create_table_title(fields, order_after, filter_conditions_customer, search_text):
279     """
280 
281     :param fields:
282     :param order_after:
283     :param filter_conditions_customer:
284     :return:
285     """
286     # """<th><span><input type="checkbox"></span>"""
287     # """<a href="?o={{ field.name }} style="display:block;font-size:14px;">{{ field.verbose_name }}</a>"""
288     # 添加一列checkbox
289     ele_checkbox = """<th><span><input type="checkbox" id="test" οnclick="select_all_checkbox(this);"></span></th>"""
290     # filter_text
291     filter_text = ''
292     for k, v in filter_conditions_customer.items():
293         temp = k + '=' + v
294         filter_text += temp + '&'
295     filter_text = filter_text.rstrip('&')
296     # 添加title
297     ele_title = ''
298     # 设置标题的href
299     for field in fields:
300         temp = order_after.lstrip('-')
301         if temp == field.name:
302             ele_title += """<th><a href="?{0}&o={1}&_q={2}">{3}</a></th>""".format(
303                 filter_text,
304                 order_after,
305                 search_text,
306                 field.verbose_name
307             )
308         else:
309             ele_title += """<th><a href="?{0}&o={1}&_q={2}">{3}</a></th>""".format(
310                 filter_text,
311                 field.name,
312                 search_text,
313                 field.verbose_name
314             )
315     table_title = ele_checkbox + ele_title
316     return mark_safe(table_title)
317 
318 
319 @register.simple_tag
320 def get_horizontal_tag_values(field, admin_class, form_object):
321     field_obj = getattr(admin_class.model, field.name)
322     query_sets_all = field_obj.rel.to.objects.all()
323     # print('===>query_sets_all', query_sets_all)
324 
325     instance_field = getattr(form_object.instance, field.name)
326     query_sets_select = instance_field.all()
327     # print('====>query_sets_select', dir(query_sets_select.union()))
328 
329     diff_query_sets = query_sets_all.difference(query_sets_select)
330     # print('====>different_query_sets', diff_query_sets)
331     return diff_query_sets
332 
333 
334 @register.simple_tag
335 def get_horizontal_field_value(field, form_object):
336     # print(form_object.instance.tags)
337     field_obj = getattr(form_object.instance, field.name)
338     selected_list = field_obj.all()
339     return selected_list

效果如下:

 

转载于:https://www.cnblogs.com/eaglesour/p/8098583.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值