• 项目一: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=" 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=" 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          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          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      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" onsubmit="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=" 300px;height: 200px" multiple name="{{ field.name }}" id="id_{{ field.name }}_from">
     71                                     {% for item in select_object_list %}
     72                                         <option ondblclick="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=" 300px;height: 200px" multiple  id="id_{{ field.name }}_to" name="{{ field.name }}">
     89                                 {% for item in get_selected_list %}
     90                                     <option ondblclick="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=" 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() + "' ondblclick=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" onclick="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" onsubmit="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() + "' ondblclick=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" onclick="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

    效果如下:

  • 相关阅读:
    写了个批量下载抖音无水印视频的小软件。
    ffmpeg转换参数码
    WPF
    使用EF的Code First模式创建模型
    桌面置顶显示服务器信息
    Assert.assertEquals
    XML报文解析思路
    定时任务,cron七域
    检查网络是否通畅
    Ngnix运行vue项目
  • 原文地址:https://www.cnblogs.com/eaglesour/p/8098583.html
Copyright © 2020-2023  润新知