CRM系统-----学员管理系统---admin自定义开发2

7.admin的自定制开发

10.实现与django admin filter_horizontal一样的复选框

实现效果:

 

首先要在king_admin中添加    filter_horizontal = ["tags"]

前段的页面:

 1 <form class="form-horizontal" role="form" method="post" onsubmit="return SeclectAllChosenDate()">
 2     {% csrf_token %}
 3     <span style="color: red">{{ form_obj.errors }}</span>
 4     {% for field in form_obj %}
 5         <div class="form-group">
 6             <label  class="col-sm-2 control-label" style="font-weight: normal">
 7                 {% if field.field.required %}
 8                     <b>{{ field.label }}:</b>
 9                 {% else %}
10                     {{ field.label }}:
11                 {% endif %}
12             </label>
13             <div class="col-sm-4">
14                 {% if field.name in admin_class.filter_horizontal %}
15                     <div class="col-md-5" >
16                         {% get_m2m_obj_list admin_class field form_obj as m2m_obj_list %}
17                         <select id="id_{{ field.name }}_from" multiple style="height: 200px!important; width: 100%;">
18                             {% for obj in m2m_obj_list %}
19                                 <option value="{{ obj.id }}" ondblclick="MoveElementTo(this,'id_{{ field.name }}_to','id_{{ field.name }}_from')">{{ obj }}</option>
20                             {% endfor %}
21                         </select>
22                     </div>
23                     <div class="col-md-1" style="margin-top: 50px">
24                        >> <<
25                     </div>
26                     <div class="col-md-5">
27                         {% get_m2m_selected_obj_list form_obj field as  m2m_selected_obj_list %}
28                         <select tags="chosen_list" id="id_{{ field.name }}_to" name="{{ field.name }}" multiple style="height: 200px!important; width: 100%;">
29                             {% for obj in m2m_selected_obj_list %}
30                                 <option value="{{ obj.id }}" ondblclick="MoveElementTo(this,'id_{{ field.name }}_from','id_{{ field.name }}_to')">{{ obj }}</option>
31                             {% endfor %}
32                         </select>
33                     </div>
34 
35                 {% else %}
36                     {{ field }}
37                 {% endif %}
38             </div>
39         </div>
40     {% endfor %}
41 
42     <div>
43         <div class="col-lg-5">
44             <button type="submit" class="btn btn-info pull-right" >保存</button>
45         </div>
46     </div>
47     </form>
table_obj_change

实现前段的tags显示:

 1 @register.simple_tag
 2 def get_m2m_obj_list(admin_class,field,form_obj):
 3     """返回待选标签数据"""
 4     field_obj =getattr(admin_class.model,field.name)
 5     all_obj_list = field_obj.rel.model.objects.all()
 6     # print("-------",field_obj,all_obj_list)
 7     if form_obj.instance.id:
 8         selected_field_obj = getattr(form_obj.instance,field.name)
 9         selected_obj_list = selected_field_obj.all()
10         # print("#########",selected_field_obj,selected_obj_list)
11     else:
12         return all_obj_list
13 
14     standby_obj_list=[]
15     for obj in all_obj_list:
16         if obj not in selected_obj_list:
17             standby_obj_list.append(obj)
18 
19     return standby_obj_list
20 
21 @register.simple_tag
22 def get_m2m_selected_obj_list(form_obj,field):
23     """返回已选标签数据"""
24     if form_obj.instance.id:
25         field_obj =getattr(form_obj.instance,field.name)
26         # print(field_obj.all())
27         return field_obj.all()
tags

注意:需要在views中的table_obj_change函数里面把admin_class传到前段

 

实现鼠标双击后标签的移动:

 1 <script>
 2     function MoveElementTo (ele,target_id,new_target_id) {
 3         var opt_ele = "<option value='" + $(ele).val() + "' ondblclick=MoveElementTo(this,'"+ new_target_id +"','"+ target_id +"')>" + $(ele).text() + "</option>";
 4         {#<option value="2" ondblclick="MoveElementTo(this,'id_tags_from','id_tags_to')">B类</option>#}
 5         {#console.log(opt_ele);#}
 6         $("#" +target_id).append(opt_ele);
 7         $(ele).remove();
 8 
 9     }
10 
11     function SeclectAllChosenDate() {
12 
13         $("select[tags='chosen_list'] option").each(function () {
14             $(this).prop("selected",true);
15 
16         });
17         return true;
18 
19     }
20 
21 </script>
table_obj_change

这是修改的标签的复选框设置,但是新增的复选框设置没有变化。。。

需要在table_obj_add函数把admin_class添加进去,然后设置

 1 @register.simple_tag
 2 def get_m2m_obj_list(admin_class,field,form_obj):
 3     """返回待选标签数据"""
 4     field_obj =getattr(admin_class.model,field.name)
 5     all_obj_list = field_obj.rel.model.objects.all()
 6     # print("-------",field_obj,all_obj_list)
 7     if form_obj.instance.id:
 8         selected_field_obj = getattr(form_obj.instance,field.name)
 9         selected_obj_list = selected_field_obj.all()
10         # print("#########",selected_field_obj,selected_obj_list)
11     else:
12         return all_obj_list
13 
14     standby_obj_list=[]
15     for obj in all_obj_list:
16         if obj not in selected_obj_list:
17             standby_obj_list.append(obj)
18 
19     return standby_obj_list
20 
21 @register.simple_tag
22 def get_m2m_selected_obj_list(form_obj,field):
23     """返回已选标签数据"""
24     if form_obj.instance.id:
25         field_obj =getattr(form_obj.instance,field.name)
26         # print(field_obj.all())
27         return field_obj.all()
tags

最终效果:

 

 后续:没有写全选设置,后续补充

11.开发删除页面

 前段写上删除按钮: 在form标签内

 1 <div class="form-group">
 2         <div class="col-sm-2">
 3 
 4             <a class="btn btn-danger" href="{% url "table_obj_delete" app_name table_name form_obj.instance.id %}">删除</a>
 5 
 6         </div>
 7         <div class="col-sm-4">
 8             <button type="submit" class="btn btn-info pull-right" >保存</button>
 9         </div>
10     </div>
table_obj_change

 

url.py

re_path('(\w+)/(\w+)/(\d+)/delete/', views.table_obj_delete, name="table_obj_delete"),

 

 views.py

 1 def table_obj_delete(request,app_name,table_name,obj_id):
 2     """删除页面"""
 3     admin_class = king_admin.enabled_admins[app_name][table_name]
 4     obj = admin_class.model.objects.get(id=obj_id)
 5 
 6     if request.method == "POST":
 7         obj.delete()
 8         return redirect("/king_admin/%s/%s/"%(app_name,table_name))
 9 
10     return render(request,"king_admin/table_obj_delete.html",{"obj":obj,
11                                                               "admin_class":admin_class,
12                                                               "app_name":app_name,
13                                                               "table_name":table_name})
Views

 

table_obj_delete.html

 1 {% extends 'king_admin/table_index.html' %}
 2 {% load tags %}
 3 {% block container %}
 4 
 5     <div>
 6         {% display_obj_related obj %}
 7         <form method="post">{% csrf_token %}
 8             <input type="submit" class="btn btn-danger" value="Yes,I'm sure" />
 9             <a class="btn btn-info" href="{% url "table_objs" app_name table_name %}" >No,Take me back</a>
10 
11         </form>
12     </div>
13 
14 {% endblock %}
table_obj_delete

 

tags.py

 1 @register.simple_tag
 2 def recursive_related_objs_lookup(objs):
 3     # model_name = objs[0]._meta.model_name
 4     ul_ele = "<ul>"
 5     print("----",objs)
 6     for obj in objs:
 7         li_ele = """<li> %s: %s</li>"""%(obj._meta.verbose_name,obj.__str__().strip("<>"))
 8         ul_ele +=li_ele
 9 
10         #for local many to many
11         for m2m_field in obj._meta.local_many_to_many:
12             sub_ul_ele = "<ul>"
13             m2m_field_obj = getattr(obj,m2m_field.name)
14             for o in m2m_field_obj.select_related():
15                 li_ele = """<li> %s: %s</li>"""%(m2m_field.verbose_name,o.__str__().strip("<>"))
16                 sub_ul_ele +=li_ele
17             sub_ul_ele += "</ul>"
18             ul_ele +=sub_ul_ele
19 
20         for related_obj in obj._meta.related_objects:
21             if "ManyToManyRel"  in related_obj.__repr__():
22                 if hasattr(obj, related_obj.get_accessor_name()):
23                     accessor_obj = getattr(obj, related_obj.get_accessor_name())
24                     # print("accessro_obj",accessor_obj)
25 
26                     if hasattr(accessor_obj, "all"):  # 查询出来所有的数据
27                         target_objs = accessor_obj.all()
28                         sub_ul_ele = "<ul style='color:red'>"
29                         for o in target_objs:
30                             li_ele = """<li> %s: %s</li>""" % (o._meta.verbose_name, o.__str__().strip("<>"))
31                             sub_ul_ele += li_ele
32                         sub_ul_ele += "</ul>"
33                         ul_ele += sub_ul_ele
34 
35 
36             elif hasattr(obj,related_obj.get_accessor_name()):
37                 accessor_obj = getattr(obj,related_obj.get_accessor_name())
38                 # print("accessro_obj",accessor_obj)
39 
40                 if hasattr(accessor_obj,"all"):# 查询出来所有的数据
41                     target_objs = accessor_obj.all()
42                     # print(target_objs)
43                 else:
44                     print("one to one i guess:",accessor_obj)
45                     target_objs = accessor_obj
46 
47                 if target_objs:
48                     nodes = recursive_related_objs_lookup(target_objs)
49                     ul_ele +=nodes
50     ul_ele +="</ul>"
51     return ul_ele
52 
53 
54 @register.simple_tag
55 def display_obj_related(objs):
56     """把对象及所有相关联的数据取出来"""
57     objs = [objs,]
58     if objs:
59         model_class = objs[0]._meta.model
60         mode_name = objs[0]._meta.model_name
61         # print(model_class,mode_name)
62         return mark_safe(recursive_related_objs_lookup(objs))
tags

 

效果:

12.action功能

实现action的功能,这样就可以自定制事件。例如:

前段页面: 设置checkbox全选和action的功能框

  1 {% extends "king_admin/table_index.html" %}
  2 {% load tags %}
  3 {% block container %}
  4 
  5     <div class="row">
  6         <div class="panel panel-info">
  7             <div class="panel-heading">
  8                 <h3 class="panel-title">{% get_bulid_name admin_class %}</h3>
  9             </div>
 10             <div>
 11                 <a href="{{ request.path }}add/">
 12                     <button  class="btn btn-info pull-right" style="margin: 10px" >增加</button>
 13                 </a>
 14             </div>
 15             <div class="panel-body">
 16                 <div class="row">
 17                     <form class="" method="get">
 18                         {% for filter_fields in admin_class.list_filters %}
 19                             <div class="col-lg-2">
 20                                 <span>{{ filter_fields }}</span>
 21                                 {% render_filter_ele filter_fields admin_class filter_condtions %}
 22                             </div>
 23                         {% endfor %}
 24                         <button type="submit" class="btn btn-info" style="margin-top: 20px">检索</button>
 25 
 26                         <div class="row">
 27                             <div class="col-lg-3">
 28                                 <input type="search" name="_q" class="form-control" style="margin: 10px 15px" value="{{ search_text }}" placeholder="----->>提示" />
 29                             </div>
 30                             <button type="submit" class="btn btn-info" style="margin: 10px 15px">搜索</button>
 31                             <span>Search by
 32                                 {% for column in admin_class.search_fields %}
 33                                     {{ column }},
 34                                 {% endfor %}
 35                             </span>
 36                         </div>
 37 
 38                     </form>
 39                 </div>
 40 
 41                 <div class="row">
 42                     <form onsubmit="return ActionSubmit(this)" method="POST">{% csrf_token %}
 43                         <span style="float: left; font-size: large;margin:10px 0px 0px 30px">Action:</span>
 44                         <div class="col-md-2"  >
 45                             <select class="form-control" id="action_list" name="action">
 46                                 <option>-------</option>
 47                                 {% for action in admin_class.actions %}
 48                                 <option value="{{ action }}">{{ action }}</option>
 49                                 {% endfor %}
 50                             </select>
 51                         </div>
 52                         <button type="submit" class="btn btn-info"  >Go</button>
 53                     </form>
 54                 </div>
 55 
 56                 <table class="table table-hover">
 57                     <thead>
 58                         <tr>
 59                             <th><input type="checkbox" onclick="CheckAllToggle(this)" /></th>
 60                             {% for column in admin_class.list_display %}
 61                                 {% bulid_table_header_column column orderby_key filter_condtions %}
 62 {#                                <th><a href="?o={{ column }}">{{ column }} </a></th>#}
 63 
 64                             {% endfor %}
 65                         </tr>
 66                     </thead>
 67                     <tbody>
 68 {#                        {% get_query_sets admin_class as query_sets %}#}
 69                         {% for obj in query_sets %}
 70                             <tr>
 71                                 <td><input tag="obj_checkbox" type="checkbox" value="{{ obj.id }}" /></td>
 72                                 {% bulid_table_row request obj admin_class %}
 73                             </tr>
 74                         {% endfor %}
 75                     </tbody>
 76 
 77                     <tfoot>
 78                         <tr>
 79                             <td></td>
 80                             <td>总共{{ query_sets.paginator.count }}条</td>
 81                         </tr>
 82                     </tfoot>
 83                 </table>
 84 
 85                 <!--<div class="pagination">
 86                   <span class="step-links">
 87                     {% if query_sets.has_previous %}
 88                         <a href="?page=1">&laquo; first</a>
 89                         <a href="?page={{ query_sets.previous_page_number }}">previous</a>
 90                     {% endif %}
 91 
 92                 <span class="current">
 93                         Page {{ query_sets.number }} of {{ query_sets.paginator.num_pages }}.
 94 
 95                 </span>
 96 
 97                     {% if query_sets.has_next %}
 98                         <a href="?page={{ query_sets.next_page_number }}">next</a>
 99                         <a href="?page={{ query_sets.paginator.num_pages }}">last &raquo;</a>
100                     {% endif %}
101                   </span>
102               </div>-->
103 
104                 <nav >
105                     <ul class="pagination">
106                       {% if query_sets.has_previous %}
107                             <li><a href="?page=1&{% page filter_condtions previous_orderby search_text %}">首页</a></li>
108                             <li>
109                                 <a href="?page={{ query_sets.previous_page_number }}&{% page filter_condtions previous_orderby search_text %}">上一页</a></li>
110                       {% endif %}
111 
112                       {% for loop_counter in query_sets.paginator.page_range %}
113                             {%  render_page_ele loop_counter query_sets filter_condtions previous_orderby search_text %}
114                       {% endfor %}
115 
116                       {% if query_sets.has_next %}
117                             <li><a href="?page={{ query_sets.next_page_number }}&{% page filter_condtions previous_orderby search_text %}">下一页</a></li>
118 
119                             <li><a href="?page={{ query_sets.paginator.num_pages }}&{% page filter_condtions previous_orderby search_text %}">尾页</a></li>
120                       {% endif %}
121                     </ul>
122                 </nav>
123 
124             </div>
125         </div>
126     </div>
127 
128 
129     <script>
130         function CheckAllToggle(ele) {
131             if ($(ele).prop("checked")){
132                 $('input[tag="obj_checkbox"]').prop("checked",true)
133             }else{
134                 $('input[tag="obj_checkbox"]').prop("checked",false)
135             }
136         }
137 
138         function ActionSubmit(form_ele) {
139            var selected_ids = [];
140            $("input[tag='obj_checkbox']:checked").each(function() {
141                selected_ids.push($(this).val());
142            });
143             var selected_action = $("#action_list").val();
144             console.log(selected_ids);
145             console.log(selected_action);
146             if (selected_ids.length == 0){
147                 alert("No object got selected!");
148 
149             }
150             if ( selected_action == "-------" ){
151                 alert("No action got selected!");
152             };
153 
154             var selected_ids_ele = "<input name='selected_ids' type='hidden' value='" + selected_ids.toString() + "'>"
155             $(form_ele).append(selected_ids_ele);
156 
157             return ture;
158 
159 
160         }
161 
162     </script>
163 {% endblock %}
table_objs.html
后端
 1 def display_table_objs(request,app_name,table_name):
 2 
 3     admin_class = king_admin.enabled_admins[app_name][table_name]
 4 
 5     if request.method == "POST":  #action is coming!!
 6         # print(request.POST)
 7         selected_ids = request.POST.get("selected_ids")
 8         action = request.POST.get("action")
 9         if selected_ids:
10             selected_objs = admin_class.model.objects.filter(id__in=selected_ids.split(","))
11         else:
12             raise KeyError("No object selected!")
13 
14         if hasattr(admin_class,action):
15             action_func = getattr(admin_class,action)
16             request._admin_action = action
17             return action_func(admin_class,request,selected_objs)
18 
19     # object_list = admin_class.model.objects.all()
20     object_list,filter_condtions = table_filter(request,admin_class)  #过滤后的结果
21 
22     object_list = table_search(request,admin_class,object_list) #搜索数据
23 
24     object_list,orderby_key = table_sort(request,admin_class,object_list) #排序后的结果
25 
26     paginator = Paginator(object_list,admin_class.list_per_page)  # Show 25 contacts per page
27     page = request.GET.get('page')
28     query_sets = paginator.get_page(page)
29 
30     return render(request, "king_admin/table_objs.html",{"admin_class":admin_class,
31                                                          "query_sets":query_sets,
32                                                          "filter_condtions":filter_condtions,
33                                                          "orderby_key":orderby_key,
34                                                          "previous_orderby":request.GET.get("o",""),
35                                                          "search_text":request.GET.get("_q",""),} )
Views
 1 class BaseAdmin(object):
 2     list_display = []
 3     list_filters = []
 4     search_fields = []
 5     list_per_page = 20
 6     ordering = None
 7     filter_horizontal = []
 8     actions = ["delete_selectd_obj",]
 9 
10     def delete_selectd_obj(self,request,querysets):
11         # print(self,request,querysets)
12         app_name = self.model._meta.app_label
13         table_name = self.model._meta.model_name
14         print(app_name,table_name)
15         if request.POST.get("delete_confirm") == "yes":
16             querysets.delete()
17             return redirect("/king_admin/%s/%s/"%(app_name,table_name))
18         selected_ids = ",".join([str(i.id) for i in querysets])
19 
20         return render(request,"king_admin/table_obj_delete.html",{"obj": querysets,
21                                                                   "admin_class":self,
22                                                                   "app_name":app_name,
23                                                                   "table_name":table_name,
24                                                                   "selected_ids":selected_ids,
25                                                                   "action":request._admin_action})
king_admin

 

 

 

 每页的action设置:

1  actions = ["delete_selectd_obj","test",]
2     def test(self,request,queryset):
3         print("in set")
4     test.dispaly_name = "测试"

table_objs.html

1 <select class="form-control" id="action_list" name="action">
2                                 <option>-------</option>
3                                 {% for action in admin_class.actions %}
4                                 <option value="{{ action }}">{% get_action_verbose_name admin_class action %} </option>
5                                 {% endfor %}
6                             </select>

tags.py

1 @register.simple_tag
2 def get_action_verbose_name( admin_class ,action):
3     action_func = getattr(admin_class,action)
4     return action_func.dispaly_name if hasattr(action_func,"dispaly_name") else action

13.readonly fields只读

在添加页面有些字段我们不想更改,这样就需要这些字段是只读的

在king_admin中添加

readonly_fields = []

 

 1 def create_model_form(request,admin_class):
 2 
 3     def __new__(cls,*args,**kwargs):
 4         for field_name,field_obj in cls.base_fields.items():
 5             field_obj.widget.attrs["class"] = "form-control"
 6             if field_name in admin_class.readonly_fields:
 7                 field_obj.widget.attrs["disabled"] = "disabled"
 8 
 9 
10         return ModelForm.__new__(cls)
forms.py

 

但是有一个问题是,只读的字段一旦保存就出现错误,不能提交数据

所以只能用ajax把标签的diabled去掉

 1  function SeclectAllChosenDate() {
 2 
 3         $("select[tags='chosen_list'] option").each(function () {
 4             $(this).prop("selected",true);
 5 
 6         });
 7         $("form").find("[disabled]").removeAttr("disabled");
 8         return true;
 9 
10     }
table_obj_change.html

 

这样就出现另外一个问题  在标签中修改数据后保存也是可以的,这就不行了。

14.kingadmin实现后端表单验证

 1    def default_clean(self):
 2         """给所有的form默认加一个clean验证"""
 3         # print(self)
 4         error_list=[]
 5         for field in admin_class.readonly_fields:
 6             field_val = getattr(self.instance,field)
 7             field_val_form_frontend = self.cleaned_data.get(field)
 8             # print(field_val,field_val_form_frontend)
 9             if field_val != field_val_form_frontend:
10                 error_list.append(ValidationError(
11                     _('Field %(field)s is readonly, data should be %(val)s'),
12                     code='invalid',
13                     params={'field':field,"val":field_val},
14                 ))
15 
16 
17         #自定制验证信息开始
18         self.ValidationError = ValidationError
19         response = admin_class.default_form_validation(self)
20         if response:
21             error_list.append(response)
22         #自定制验证信息结束
23 
24         if error_list:
25             raise ValidationError(error_list)
26 
27 
28  setattr(_model_form_class,"clean",default_clean)
forms

 在customer中添加自定制验证信息:

1   def default_form_validation(self):
2         """定义一个自定制的验证"""
3         consult_content = self.cleaned_data.get("content","")
4         if len(consult_content) < 15:
5             return self.ValidationError(
6                     ('Field %(field)s is 咨询的内容不能小于15个字符'),
7                     code='invalid',
8                     params={'field':"content"},)
king_admin

 

 效果:

 

 单个字段的验证:

在customer中king_admin:

1    def clean_name(self):
2         """定义单个字段的验证"""
3         if not self.cleaned_data["name"]:
4             self.add_error("name","name is not null"
 1  def __new__(cls,*args,**kwargs):
 2         for field_name,field_obj in cls.base_fields.items():
 3             field_obj.widget.attrs["class"] = "form-control"
 4             if field_name in admin_class.readonly_fields:
 5                 field_obj.widget.attrs["disabled"] = "disabled"
 6 
 7 
 8             #定义单个字段的验证
 9             if hasattr(admin_class,"clean_%s"%field_name):
10                 field_clean_func = getattr(admin_class,"clean_%s"%field_name)
11                 setattr(cls,"clean_%s"%field_name,field_clean_func)
12 
13         return ModelForm.__new__(cls)
forms

 

效果:

 

 

针对m2m的tags字段的readonly验证:

 1  def default_clean(self):
 2         """给所有的form默认加一个clean验证"""
 3         # print(self)
 4         error_list=[]
 5         for field in admin_class.readonly_fields:
 6             field_val = getattr(self.instance,field)  #val in db
 7 
 8             if hasattr(field_val,"select_related"):#m2m 
 9                 m2m_objs=getattr(field_val,"select_related")().select_related()
10                 m2m_vals = [ i[0] for i in m2m_objs.values_list("id")]
11                 set_m2m_vals = set(m2m_vals)
12                 set_m2m_from_frontend =set([i.id for i in self.cleaned_data.get(field)])
13                 if set_m2m_vals != set_m2m_from_frontend:
14                     self.add_error(field,"readonly field")
15                 continue
16 
17 
18 
19             field_val_form_frontend = self.cleaned_data.get(field)
20             # print(field_val,field_val_form_frontend)
21             if field_val != field_val_form_frontend:
22                 error_list.append(ValidationError(
23                     _('Field %(field)s is readonly, data should be %(val)s'),
24                     code='invalid',
25                     params={'field':field,"val":field_val},
26                 ))
27 
28 
29         #自定制验证信息开始
30         self.ValidationError = ValidationError
31         response = admin_class.default_form_validation(self)
32         if response:
33             error_list.append(response)
34         #自定制验证信息结束
35 
36         if error_list:
37             raise ValidationError(error_list)
forms
 1     <div class="col-sm-4">
 2                 {% if field.name in admin_class.filter_horizontal %}
 3                     <div class="col-md-5" >
 4                         {% get_m2m_obj_list admin_class field form_obj as m2m_obj_list %}
 5                             <select id="id_{{ field.name }}_from" multiple style="height: 200px!important; width: 100%;">
 6                             {% if field.name in admin_class.readonly_fields %}
 7                                 {% for obj in m2m_obj_list %}
 8                                     <option value="{{ obj.id }}" >{{ obj }}</option>
 9                                 {% endfor %}
10                             {% else %}
11                                 {% for obj in m2m_obj_list %}
12                                     <option value="{{ obj.id }}" ondblclick="MoveElementTo(this,'id_{{ field.name }}_to','id_{{ field.name }}_from')">{{ obj }}</option>
13                                 {% endfor %}
14                             {% endif %}
15 
16                         </select>
17                     </div>
18                     <div class="col-md-1" style="margin-top: 50px">
19                        >> <<
20                     </div>
21                     <div class="col-md-5">
22                         {% get_m2m_selected_obj_list form_obj field as  m2m_selected_obj_list %}
23                         <select tags="chosen_list" id="id_{{ field.name }}_to" name="{{ field.name }}" multiple style="height: 200px!important; width: 100%;">
24                             {% if field.name in admin_class.readonly_fields %}
25                                 {% for obj in m2m_selected_obj_list %}
26                                     <option value="{{ obj.id }}" >{{ obj }}</option>
27                                 {% endfor %}
28                             {% else %}
29                                 {% for obj in m2m_selected_obj_list %}
30                                     <option value="{{ obj.id }}" ondblclick="MoveElementTo(this,'id_{{ field.name }}_from','id_{{ field.name }}_to')">{{ obj }}</option>
31                                 {% endfor %}
32                             {% endif %}
33 
34                         </select>
35                     </div>
36 
37                 {% else %}
38                     {{ field }}<span style="color: red">{{ field.errors }}</span>
39                 {% endif %}
40             </div>
table_obj_change

15.king_admin实现创建数据时不进行readonly fields验证

 

 1     def __new__(cls,*args,**kwargs):
 2         for field_name,field_obj in cls.base_fields.items():
 3             field_obj.widget.attrs["class"] = "form-control"
 4 
 5             if  not hasattr(admin_class,"is_add_form"): #这是表示add表单的时候,不需要disabled
 6                 if field_name in admin_class.readonly_fields:
 7                     field_obj.widget.attrs["disabled"] = "disabled"
 8 
 9 
10             #定义单个字段的验证
11             if hasattr(admin_class,"clean_%s"%field_name):
12                 field_clean_func = getattr(admin_class,"clean_%s"%field_name)
13                 setattr(cls,"clean_%s"%field_name,field_clean_func)
14 
15         return ModelForm.__new__(cls)
16 
17     def default_clean(self):
18         """给所有的form默认加一个clean验证"""
19         # print(self)
20         error_list=[]
21         if self.instance.id: #这是修改表单
22             for field in admin_class.readonly_fields:
23                 field_val = getattr(self.instance,field)  #val in db
24 
25                 if hasattr(field_val,"select_related"):#m2m
26                     m2m_objs=getattr(field_val,"select_related")().select_related()
27                     m2m_vals = [ i[0] for i in m2m_objs.values_list("id")]
28                     set_m2m_vals = set(m2m_vals)
29                     set_m2m_from_frontend =set([i.id for i in self.cleaned_data.get(field)])
30                     if set_m2m_vals != set_m2m_from_frontend:
31                         self.add_error(field,"readonly field")
32                     continue
33 
34                 field_val_form_frontend = self.cleaned_data.get(field)
35                 # print(field_val,field_val_form_frontend)
36                 if field_val != field_val_form_frontend:
37                     error_list.append(ValidationError(
38                         _('Field %(field)s is readonly, data should be %(val)s'),
39                         code='invalid',
40                         params={'field':field,"val":field_val},
41                     ))
forms
 1 def table_obj_add(request,app_name,table_name):
 2     """添加页面"""
 3     admin_class = king_admin.enabled_admins[app_name][table_name]
 4     admin_class.is_add_form = True
 5     model_class_form = create_model_form(request, admin_class)
 6 
 7 
 8     if request.method == "POST":
 9         form_obj = model_class_form(request.POST)
10         if form_obj.is_valid():
11             form_obj.save()
12             return redirect(request.path.replace("/add/","/"))
13     else:
14         form_obj = model_class_form()
15 
16     return render(request, "king_admin/table_obj_add.html", {"form_obj": form_obj,"admin_class":admin_class,"app_name":app_name,"table_name":table_name})
views
1 {% if field.name in admin_class.readonly_fields and not admin_class.is_add_form %}
table_obj_change

16.king admin实现整张表的只读

 

 

 

17.King admin的动态url菜单优化

 1 class Menu(models.Model):
 2     """菜单表"""
 3     name = models.CharField(max_length=32)
 4     url_type_choice = ((0,"alias"),(1,"absolute_url"))
 5     url_type = models.SmallIntegerField(choices=url_type_choice,default=0)
 6     url_name = models.CharField(max_length=64)
 7 
 8     def __str__(self):
 9         return self.name
10 
11     class Meta:
12         verbose_name = "菜单表"
13         verbose_name_plural = "菜单表"
models
 1 <div class="col-sm-3 col-md-2 sidebar">
 2           <ul class="nav nav-sidebar">
 3               {% for role in request.user.userprofile.roles.all %}
 4                 {% for menu in role.menus.all %}
 5                     <li class=""><a href="{% if menu.url_type == 0 %}{% url menu.url_name %}{% else %}{{ menu.url_name }}{% endif %}">{{ menu.name }}</a></li>
 6                 {% endfor %}
 7               {% endfor %}
 8           </ul>
 9 
10         </div>
index.html

这样设置只能是跳转到其他的页面。

 

 

 

 

 

 

 

####################################################

posted @ 2018-08-15 21:28  Garrett0220  阅读(243)  评论(0编辑  收藏  举报
levels of contents