7.admin的自定制开发

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

实现效果:

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

前段的页面:

 1 <form class="form-horizontal" role="form" method="post" οnsubmit="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 }}" οndblclick="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 }}" οndblclick="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() + "' οndblclick=MoveElementTo(this,'"+ new_target_id +"','"+ target_id +"')>" + $(ele).text() + "</option>";
 4         {#<option value="2" οndblclick="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 }}" οndblclick="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 }}" οndblclick="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

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

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

转载于:https://www.cnblogs.com/garrett0220/articles/9473236.html

CRM系统-----学员管理系统---admin自定义开发2相关推荐

  1. CRM系统-----学员管理系统---admin自定义开发3

    admin的自定制开发 18.django实现自定义用户认证 1 from django.db import models 2 from django.contrib.auth.models impo ...

  2. CRM系统-----学员管理系统

    1.需求分析 2.使用组件 django2.0+bootstrap3.37+jquery1.12+mysql8.0 django2.1:https://www.djangoproject.com/ 3 ...

  3. 客户关系管理系统 java_Java高级项目实战02:客户关系管理系统CRM系统模块分析与介绍...

    先来CRM系统结构图: 每个模块作用介绍如下: 1.营销管理 营销机会管理:针对企业中客户的质询需求所建立的信息录入功能,方便销售人员进行后续的客户需求跟踪与联系,提高企业客户购买产品的几率. 营销开 ...

  4. 基于java的CRM客户关系管理系统的设计与实现

    本科毕业设计(论文) 题 目: 基于java的CRM客户关系管理系统的设计与实现 专题题目: 说 明 请按以下顺序编排: 封面 任务书 开题报告 中外文摘要及关键词 目录 正文 附录(可选) 参考文献 ...

  5. 简信CRM系统:移动CRM系统让销售工作更顺利展开

    企业在管理和销售的过程中总是会遇到各种各样的问题,以下场景都是企业经常会遇到的: 1.销售人员在路上接到了客户的电话,可是这个客户已经很久没有和自己进行沟通了,销售员甚至想不起来对方是做什么的.这时候 ...

  6. 移动CRM系统让销售工作更顺利展开

    企业在管理和销售的过程中总是会遇到各种各样的问题,以下场景都是企业经常会遇到的: 1.销售人员在路上接到了客户的电话,可是这个客户已经很久没有和自己进行沟通了,销售员甚至想不起来对方是做什么的.这时候 ...

  7. 【分享】如何自动同步企业微信外部客户信息到CRM系统?

    许多企业的销售人员利用企业微信添加外部客户,与客户沟通,但是销售添加外部客户后并不加外部客户录入到企业CRM中.另外,即便是录入了客户到企业CRM系统中,也经常不去更新外部联系人的信息变化到企业CRM ...

  8. java计算机毕业设计-移动公司crm客户关系管理系统开发与实现-源程序+mysql+系统+lw文档+远程调试

    java计算机毕业设计-移动公司crm客户关系管理系统开发与实现-源程序+mysql+系统+lw文档+远程调试 java计算机毕业设计-移动公司crm客户关系管理系统开发与实现-源程序+mysql+系 ...

  9. CRM系统源码|客户管理系统源码开发

    CRM是指客户关系管理.它包括使企业能够形成.管理和跟踪与客户的关系和通信以促进业务增长的流程和系统,但 CRM 是基于传统系统,如基于网络和零售商店.电话或传真客户联系.在客户关系管理中,关系的性质 ...

最新文章

  1. CRM系统业务的分析(1)
  2. 细说Android事件传递
  3. 基于JSP的开题报告定做
  4. oracle创建用户、授予权限及删除用户
  5. best tips for databases for graduate research
  6. android 提示文字,EditText 不能显示提示文字Hint
  7. data.frame 转化为数值型_DataFrame(3):DataFrame的创建方式
  8. CF1090F - How to Learn You Score(构造)
  9. ubuntu 修改用户名和计算机名称
  10. E-MapReduce解决hive comment中文乱码问题
  11. 03 | 事务隔离:为什么你改了我还看不见?笔记(转)
  12. java 时间换算_【时间工具】整理下java时间换算专题
  13. mysql选择utf 8编码_MySQL支持UTF-8编码全攻略
  14. stringbuilder_String,StringBuilder,StringBuffer三者的区别?
  15. Android学习JNI,使用JNI实现字符串加密
  16. Oracle数据库操作基本语法
  17. GCJ-02火星坐标系和WGS-84坐标系转换关系
  18. 《Adobe Photoshop CS6中文版经典教程(彩色版)》目录—导读
  19. Xposed 企业微信 Hook 微信
  20. R_leaflet包_最易上手地图教程(二)

热门文章

  1. 第六章 使用scikit-learn构建模型
  2. 持安科技CEO何艺:零信任在实战攻防演练中的价值
  3. 等保系列之——网络安全等级保护测评:工作流程及工作内容
  4. cad放大_左手快捷键,右手鼠标,这就是CAD!
  5. spring框架aop_使用Spring框架和AOP进行动态路由
  6. 计算机专业英语选择题,计算机专业英语单选题
  7. 论文精读-基于双目图像的视差估计方法研究以及实现
  8. AI绘画火了!一文看懂背后技术原理
  9. 【认识硬件】之 水泥电阻
  10. 解决每次新建word都有页眉和页脚