CRM系统-----学员管理系统---admin自定义开发
7.admin的自定制开发
为了更好的兼容性和开发,我们自定制一个admin(命名为king admin) 区别于django的admin,可以更好的兼容我们的系统和软件
1.开发King admin 的数据库表列表页
新建app---->king amin 然后新建king_admin.py
1 from django.urls import path, re_path 2 from king_admin import views 3 4 urlpatterns = [ 5 path('index/', views.index,name="table_index"), 6 re_path('(\w+)/(\w+)/', views.display_table_objs,name="table_objs"), 7 8 ]
1 from crm import models 2 3 4 5 enabled_admins = {} 6 7 class BaseAdmin(object): 8 list_display = [] 9 list_filter = [] 10 11 class CustomerAdmin(BaseAdmin): 12 list_display = ["qq","name","source","consult_course","date","consultant"] 13 14 class CustomerFollowUpAdmin(BaseAdmin): 15 list_display = ["customer","consultant","date","intention"] 16 17 class CourseAdmin(BaseAdmin): 18 list_display = ["name"] 19 20 21 22 23 def register(model_class,admin_class=None): 24 if model_class._meta.app_label not in enabled_admins: 25 enabled_admins[model_class._meta.app_label]={} 26 27 admin_class.model = model_class 28 enabled_admins[model_class._meta.app_label][model_class._meta.model_name] = admin_class 29 30 31 32 33 34 register(models.Customer,CustomerAdmin) 35 register(models.CustomerFollowUp,CustomerFollowUpAdmin) 36 register(models.Course,CourseAdmin)
1 from django.shortcuts import render 2 3 # Create your views here. 4 from king_admin import king_admin 5 6 7 def index(request): 8 # print(king_admin.enabled_admins["crm"]["course"]) 9 10 return render(request,"king_admin/table_index.html",{"table_list":king_admin.enabled_admins}) 11 12 13 def display_table_objs(request,app_name,table_name): 14 15 16 admin_class = king_admin.enabled_admins[app_name][table_name] 17 18 return render(request, "king_admin/table_objs.html",{"admin_class":admin_class} )
1 {% extends "base.html" %} 2 {% load tags %} 3 {% block body %} 4 <body> 5 6 <nav class="navbar navbar-inverse navbar-fixed-top"> 7 <div class="container-fluid"> 8 <div class="navbar-header"> 9 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> 10 <span class="sr-only">Toggle navigation</span> 11 <span class="icon-bar"></span> 12 <span class="icon-bar"></span> 13 <span class="icon-bar"></span> 14 </button> 15 <a class="navbar-brand" href="#">PerfectCRM</a> 16 </div> 17 <div id="navbar" class="navbar-collapse collapse"> 18 <ul class="nav navbar-nav navbar-right"> 19 <li><a href="#">{{ request.user }}</a></li> 20 </ul> 21 </div> 22 </div> 23 </nav> 24 25 <div class="container" style="margin: 30px;width: auto"> 26 {% block container %} 27 <div class="row"> 28 <div class="panel panel-info"> 29 <div class="panel-heading"> 30 <h3 class="panel-title">Panel title</h3> 31 </div> 32 <div class="panel-body"> 33 {# {{ table_list }}#} 34 {% for app_name,app_table in table_list.items %} 35 <table class="table table-hover"> 36 <thead> 37 <tr> 38 <th>{{ app_name }}</th> 39 </tr> 40 </thead> 41 <tbody> 42 {% for table_name,admin in app_table.items %} 43 <tr> 44 <td><a href="{% url 'table_objs' app_name table_name %} "> 45 {% render_app_name admin %}</a></td> 46 <td>add</td> 47 <td>change</td> 48 </tr> 49 {% endfor %} 50 </tbody> 51 </table> 52 {% endfor %} 53 </div> 54 </div> 55 </div> 56 {% endblock %} 57 </div> 58 59 60 </body> 61 {% endblock %}
我们需要显示的列表名为汉字,所以才创建自定义标签
新建templatetags---->tags.py
1 from django import template 2 from django.utils.safestring import mark_safe 3 4 register = template.Library() 5 6 @register.simple_tag 7 def render_app_name(admin_class): 8 return admin_class.model._meta.verbose_name
最终的效果:
2.king admin通用的数据列表展示页
首先是数据列表继承table_index.html把样式继承过来
1 {% extends "king_admin/table_index.html" %} 2 {% load tags %} 3 4 {% block container %} 5 <div class="row"> 6 <div class="panel panel-info"> 7 <div class="panel-heading"> 8 <h3 class="panel-title">Panel title</h3> 9 </div> 10 <div class="panel-body"> 11 12 <table class="table table-hover"> 13 <thead> 14 <tr> 15 {% for column in admin_class.list_display %} 16 <th>{{ column }}</th> 17 {% endfor %} 18 </tr> 19 </thead> 20 <tbody> 21 {% get_query_sets admin_class as query_sets %} 22 {% for obj in query_sets %} 23 <tr> 24 {% bulid_table_row obj admin_class %} 25 </tr> 26 {% endfor %} 27 </tbody> 28 </table> 29 30 </div> 31 </div> 32 </div> 33 {% endblock %}
1 from django import template 2 from django.utils.safestring import mark_safe 3 4 register = template.Library() 5 6 @register.simple_tag 7 def render_app_name(admin_class): 8 return admin_class.model._meta.verbose_name 9 10 11 @register.simple_tag 12 def get_query_sets(admin_class): 13 return admin_class.model.objects.all() 14 15 from django.utils.safestring import mark_safe 16 @register.simple_tag 17 def bulid_table_row(obj,admin_class): 18 row_ele = "" 19 for column in admin_class.list_display: 20 field_obj = obj._meta.get_field(column) 21 if field_obj.choices: 22 column_date = getattr(obj,"get_%s_display" % column)() 23 else: 24 column_date = getattr(obj,column) 25 26 if type(column_date).__name__ == "datetime": 27 column_date = column_date.strftime("%Y-%m-%d %H:%M:%S") 28 29 row_ele += "<td>%s</td>" % column_date 30 return mark_safe(row_ele)
标题的显示:
<thead> <tr> {% for column in admin_class.list_display %} <th>{{ column }}</th> {% endfor %} </tr> </thead>
数据库数据的显示,我们不能直接在前段显示取出数据库的数据,所以我们用自定义标签
@register.simple_tag def get_query_sets(admin_class): return admin_class.model.objects.all()
前段显示:
<tbody> {% get_query_sets admin_class as query_sets %} {% for obj in query_sets %} <tr> <td> {{ obj }}</td> </tr> {% endfor %} </tbody>
全部数据的显示
<tbody> {% get_query_sets admin_class as query_sets %} {% for obj in query_sets %} <tr> {% bulid_table_row obj admin_class %} </tr> {% endfor %} </tbody>
from django.utils.safestring import mark_safe @register.simple_tag def bulid_table_row(obj,admin_class): row_ele = "" for column in admin_class.list_display: field_obj = obj._meta.get_field(column) if field_obj.choices: column_date = getattr(obj,"get_%s_display" % column)() else: column_date = getattr(obj,column) row_ele += "<td>%s</td>" % column_date return mark_safe(row_ele)
PS:关于source的取值和显示,主要是obj._meta.get_field.choices,然后反射getattr出结果。
关于时间的显示格式,在tags中添加下面的代码:
1 if type(column_date).__name__ == "datetime":
2 column_date = column_date.strftime("%Y-%m-%d %H:%M:%S")
3.king admin的分页功能
数据的分页一般显示下数据下面,通常有首页--上一页----指定页----下一页---尾页组成,我们可以使用django自带的分页功能
views.py
1 def display_table_objs(request,app_name,table_name): 2 3 admin_class = king_admin.enabled_admins[app_name][table_name] 4 5 object_list = admin_class.model.objects.all() 6 paginator = Paginator(object_list, 2) # Show 2 contacts per page 7 page = request.GET.get('page') 8 query_sets = paginator.get_page(page) 9 10 return render(request, "king_admin/table_objs.html",{"admin_class":admin_class,"query_sets":query_sets} )
table_objs.html
<div class="panel-body"> <table class="table table-hover"> <thead> <tr> {% for column in admin_class.list_display %} <th>{{ column }}</th> {% endfor %} </tr> </thead> <tbody> {% for obj in query_sets %} <tr> {% bulid_table_row obj admin_class %} </tr> {% endfor %} </tbody> </table> <nav > <ul class="pagination"> {% if query_sets.has_previous %} <li><a href="?page=1">首页</a></li> <li><a href="?page={{ query_sets.previous_page_number }}">上一页</a></li> {% endif %} {% for loop_counter in query_sets.paginator.page_range %} {% render_page_ele loop_counter query_sets%} {% endfor %} {% if query_sets.has_next %} <li><a href="?page={{ query_sets.next_page_number }}">下一页</a></li> <li><a href="?page={{ query_sets.paginator.num_pages }}">尾页</a></li> {% endif %} </ul> </nav> </div>
tags.py
1 @register.simple_tag 2 def render_page_ele(loop_counter,query_sets): 3 4 if abs(query_sets.number - loop_counter) <=2: 5 ele_class = "" 6 if query_sets.number == loop_counter: 7 ele_class = "active" 8 ele ="<li class=%s><a href='?page=%s'>%s</a></li>"%(ele_class,loop_counter,loop_counter) 9 return mark_safe(ele) 10 11 return ""
显示效果:
4.king admin开发多条件过滤功能
table_obj.html文件的table下面插入下面代码
1 <div class="row"> 2 <form class="" method="get"> 3 {% for condtion in admin_class.list_filters %} 4 <div class="col-lg-2"> 5 <span>{{ condtion }}</span> 6 {% render_filter_ele condtion admin_class filter_condtions %} 7 </div> 8 {% endfor %} 9 <button type="submit" class="btn btn-info" style="margin-top: 20px">搜索</button> 10 </form> 11 </div>
1 @register.simple_tag 2 def render_filter_ele(condtion,admin_class,filter_condtions): 3 select_ele = "<select class='form-control' name= '%s' ><option value=''>----</option>"%condtion 4 field_obj = admin_class.model._meta.get_field(condtion) 5 if field_obj.choices: 6 selected = "" 7 for choice_item in field_obj.choices: 8 if filter_condtions.get(condtion) == str(choice_item[0]): 9 selected = "selected" 10 select_ele +="""<option value='%s' %s>%s</option>"""%(choice_item[0],selected,choice_item[1]) 11 selected='' 12 if type(field_obj).__name__ == "ForeignKey": 13 selected = "" 14 for choice_item in field_obj.get_choices()[1:]: 15 if filter_condtions.get(condtion) == str(choice_item[0]): 16 selected = "selected" 17 select_ele +="""<option value='%s' %s>%s</option>"""%(choice_item[0],selected,choice_item[1]) 18 selected='' 19 select_ele += "</select>" 20 return mark_safe(select_ele)
1 def display_table_objs(request,app_name,table_name): 2 3 admin_class = king_admin.enabled_admins[app_name][table_name] 4 5 # object_list = admin_class.model.objects.all() 6 object_list,filter_condtions = table_filter(request,admin_class) 7 paginator = Paginator(object_list,admin_class.list_per_page) # Show 25 contacts per page 8 page = request.GET.get('page') 9 query_sets = paginator.get_page(page) 10 11 return render(request, "king_admin/table_objs.html",{"admin_class":admin_class,"query_sets":query_sets,"filter_condtions":filter_condtions} )
新建utils.py
1 def table_filter(request,admin_class): 2 """进行数据过滤然后返回过滤后的结果""" 3 4 filter_condtions = {} 5 for k,v in request.GET.items(): 6 if v: 7 filter_condtions[k] = v 8 9 return admin_class.model.objects.filter(**filter_condtions),filter_condtions
最终显示效果:
PS:上面的代码还存在一些BUG 当搜索出来的数据多到分许多页 这样跳转到不同页面出错。
优化一下分页的功能并解决一下BUG
1 @register.simple_tag 2 def render_page_ele(loop_counter,query_sets,filter_condtions): 3 filters = "" 4 for k,v in filter_condtions.items(): 5 filters += "&%s=%s" %(k,v) 6 7 if abs(query_sets.number - loop_counter) <=2: 8 ele_class = "" 9 if query_sets.number == loop_counter: 10 ele_class = "active" 11 ele ="<li class=%s><a href='?page=%s%s'>%s</a></li>"%(ele_class,loop_counter,filters,loop_counter) 12 return mark_safe(ele) 13 14 return "" 15 16 @register.simple_tag 17 def page(filter_condtions): 18 filters = "" 19 for k, v in filter_condtions.items(): 20 filters += "%s=%s" % (k, v) 21 return mark_safe(filters) 22 return ""
1 <nav > 2 <ul class="pagination"> 3 {% if query_sets.has_previous %} 4 <li><a href="?page=1&{% page filter_condtions %}">首页</a></li> 5 <li> 6 <a href="?page={{ query_sets.previous_page_number }}&{% page filter_condtions %}">上一页</a></li> 7 {% endif %} 8 9 {% for loop_counter in query_sets.paginator.page_range %} 10 {% render_page_ele loop_counter query_sets filter_condtions%} 11 {% endfor %} 12 13 {% if query_sets.has_next %} 14 <li><a href="?page={{ query_sets.next_page_number }}&{% page filter_condtions %}">下一页</a></li> 15 16 <li><a href="?page={{ query_sets.paginator.num_pages }}&{% page filter_condtions %}">尾页</a></li> 17 {% endif %} 18 19 </ul> 20 </nav>
1 def table_filter(request,admin_class): 2 """进行数据过滤然后返回过滤后的结果""" 3 4 filter_condtions = {} 5 for k,v in request.GET.items(): 6 if k == "page": 7 continue 8 if v: 9 filter_condtions[k] = v 10 11 # print(filter_condtions) 12 13 return admin_class.model.objects.filter(**filter_condtions),filter_condtions
日期字段的过滤
1 from django.utils.timezone import datetime,timedelta 2 3 @register.simple_tag 4 def render_filter_ele(filter_fields,admin_class,filter_condtions): 5 select_ele = "<select class='form-control' name= '{filter_fields}' ><option value=''>----</option>" 6 field_obj = admin_class.model._meta.get_field(filter_fields) 7 if field_obj.choices: 8 selected = "" 9 for choice_item in field_obj.choices: 10 if filter_condtions.get(filter_fields) == str(choice_item[0]): 11 selected = "selected" 12 select_ele +="""<option value='%s' %s>%s</option>"""%(choice_item[0],selected,choice_item[1]) 13 selected='' 14 if type(field_obj).__name__ == "ForeignKey": 15 selected = "" 16 for choice_item in field_obj.get_choices()[1:]: 17 if filter_condtions.get(filter_fields) == str(choice_item[0]): 18 selected = "selected" 19 select_ele +="""<option value='%s' %s>%s</option>"""%(choice_item[0],selected,choice_item[1]) 20 selected='' 21 22 if type(field_obj).__name__ in ["DateField","DateTimeField"]: 23 date_els = [] 24 today_els = datetime.now().date() 25 date_els.append(["今天",today_els]) 26 date_els.append(["昨天",today_els - timedelta(days=1)]) 27 date_els.append(["近7天",today_els - timedelta(days=7)]) 28 date_els.append(["近30天",today_els - timedelta(days=30)]) 29 date_els.append(["近90天",today_els - timedelta(days=90)]) 30 date_els.append(["近180天",today_els - timedelta(days=180)]) 31 date_els.append(["本月",today_els.replace(day=1)]) 32 date_els.append(["本年",today_els.replace(month=1,day=1)]) 33 selected = "" 34 for item in date_els: 35 select_ele += """<option value='%s' %s>%s</option>""" % (item[1], selected, item[0]) 36 37 filter_fields_name = "%s__gte"%filter_fields 38 else: 39 filter_fields_name = filter_fields 40 select_ele += "</select>" 41 select_ele = select_ele.format(filter_fields=filter_fields_name) 42 return mark_safe(select_ele)
优化日期过滤的时候页面显示是那个字段的过滤
1 selected = "" #在页面上显示选择的数据 设置selected空 2 for item in date_els: 3 # print(type(item[1]),type(filter_condtions["date__gte"])) 4 if filter_condtions["date__gte"] == str(item[1]):#在页面上显示选择的数据 5 selected = "selected" #加入selected 6 select_ele += """<option value='%s' %s>%s</option>""" % (item[1],selected,item[0]) 7 selected = "" 8 filter_fields_name = "%s__gte"%filter_fields
5.king admin 的排序功能
1 <table class="table table-hover"> 2 <thead> 3 <tr> 4 {% for column in admin_class.list_display %} 5 {% bulid_table_header_column column orderby_key filter_condtions %} 6 {# <th><a href="?o={{ column }}">{{ column }} </a></th>#} 7 8 {% endfor %} 9 </tr> 10 </thead>
1 def table_sort(request,admin_class,obj): 2 orderby_key = request.GET.get("o") 3 if orderby_key: 4 res = obj.order_by(orderby_key) 5 if orderby_key.startswith("-"): 6 orderby_key = orderby_key.strip("-") 7 else: 8 orderby_key = "-%s"%orderby_key 9 else: 10 res=obj 11 12 return res,orderby_key
1 def display_table_objs(request,app_name,table_name): 2 3 admin_class = king_admin.enabled_admins[app_name][table_name] 4 5 # object_list = admin_class.model.objects.all() 6 object_list,filter_condtions = table_filter(request,admin_class) #过滤后的结果 7 8 object_list,orderby_key = table_sort(request,admin_class,object_list) #排序后的结果 9 10 paginator = Paginator(object_list,admin_class.list_per_page) # Show 25 contacts per page 11 page = request.GET.get('page') 12 query_sets = paginator.get_page(page) 13 14 return render(request, "king_admin/table_objs.html",{"admin_class":admin_class, 15 "query_sets":query_sets, 16 "filter_condtions":filter_condtions, 17 "orderby_key":orderby_key, 18 "previous_orderby":request.GET.get("o","")} )
1 @register.simple_tag 2 def bulid_table_header_column(column,orderby_key,filter_condtions): 3 filters = "" 4 for k, v in filter_condtions.items(): 5 filters += "&%s=%s" % (k, v) 6 7 ele = """<th><a href="?{filters}&o={orderby_key}">{column}</a>{icon}</th>""" 8 # print(orderby_key,column) 9 # < span class ="glyphicon glyphicon-arrow-down" aria-hidden="true" > < / span > 10 if orderby_key: 11 if orderby_key.startswith("-"): 12 icon = """<span class ="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>""" 13 else: 14 icon = """<span class ="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>""" 15 16 if orderby_key.strip("-") == column : # 确定排序的是那个字段 17 orderby_key = orderby_key 18 else: 19 orderby_key =column 20 icon="" 21 else: 22 orderby_key = column 23 icon="" 24 res = ele.format(orderby_key=orderby_key,column=column,icon=icon,filters=filters) 25 return mark_safe(res)
优化一下排序:默认排序
在king_admin中的BaseAdmin中设置ordering=None
然后在其他表中设置排序的字段名称 举个栗子:
ordering="id" 是按照id排序
ordering=“qq”是按照qq排序
最后后端处理
1 def table_filter(request,admin_class): 2 """进行数据过滤然后返回过滤后的结果""" 3 4 filter_condtions = {} 5 keywords = ["page","o","_q"] 6 for k,v in request.GET.items(): 7 if k in keywords: #保留的分页关键字和排序关键字 8 continue 9 if v: 10 filter_condtions[k] = v 11 12 # print(filter_condtions) 13 14 return admin_class.model.objects.filter(**filter_condtions).order_by\ 15 ("-%s"%admin_class.ordering if admin_class.ordering else "-id"),filter_condtions,
6.king admin 的动态搜索功能
搜索表中的数据,应该是在过滤后的数据也可以搜索的,因为搜索框应该在form表单中
1 <form class="" method="get"> 2 {% for condtion in admin_class.list_filters %} 3 <div class="col-lg-2"> 4 <span>{{ condtion }}</span> 5 {% render_filter_ele condtion admin_class filter_condtions %} 6 </div> 7 {% endfor %} 8 <button type="submit" class="btn btn-info" style="margin-top: 20px">检索</button> 9 10 <div class="row"> 11 <div class="col-lg-3"> 12 <input type="search" name="_q" class="form-control" style="margin: 10px 15px" value="{{ search_text }}" /> 13 </div> 14 <button type="submit" class="btn btn-info" style="margin: 10px 15px">搜索</button> 15 </div> 16 17 </form>
1 def display_table_objs(request,app_name,table_name): 2 3 admin_class = king_admin.enabled_admins[app_name][table_name] 4 5 # object_list = admin_class.model.objects.all() 6 object_list,filter_condtions = table_filter(request,admin_class) #过滤后的结果 7 8 object_list = table_search(request,admin_class,object_list) #搜索数据 9 10 object_list,orderby_key = table_sort(request,admin_class,object_list) #排序后的结果 11 12 paginator = Paginator(object_list,admin_class.list_per_page) # Show 25 contacts per page 13 page = request.GET.get('page') 14 query_sets = paginator.get_page(page) 15 16 return render(request, "king_admin/table_objs.html",{"admin_class":admin_class, 17 "query_sets":query_sets, 18 "filter_condtions":filter_condtions, 19 "orderby_key":orderby_key, 20 "previous_orderby":request.GET.get("o",""), 21 "search_text":request.GET.get("_q",""),} )
1 from django.db.models import Q 2 def table_search(request,admin_class,obj): 3 search_key = request.GET.get("_q","") 4 q_obj = Q() 5 q_obj.connector = "OR" 6 for column in admin_class.search_fields: 7 q_obj.children.append(("%s__contains"%column,search_key)) 8 9 res = obj.filter(q_obj) 10 return res
显示效果:
PS:
这里有几个BUG需要处理下:
1.排序上排序处理的结果和搜索出来的结果点击下一页或者上一页是出错的问题
1 <nav > 2 <ul class="pagination"> 3 {% if query_sets.has_previous %} 4 <li><a href="?page=1&{% page filter_condtions previous_orderby search_text %}">首页</a></li> 5 <li> 6 <a href="?page={{ query_sets.previous_page_number }}&{% page filter_condtions previous_orderby search_text %}">上一页</a></li> 7 {% endif %} 8 9 {% for loop_counter in query_sets.paginator.page_range %} 10 {% render_page_ele loop_counter query_sets filter_condtions previous_orderby search_text %} 11 {% endfor %} 12 13 {% if query_sets.has_next %} 14 <li><a href="?page={{ query_sets.next_page_number }}&{% page filter_condtions previous_orderby search_text %}">下一页</a></li> 15 16 <li><a href="?page={{ query_sets.paginator.num_pages }}&{% page filter_condtions previous_orderby search_text %}">尾页</a></li> 17 {% endif %} 18 19 </ul> 20 </nav>
只需要在前段把previous_orderby和search_text添加到自定义标签中后端处理
1 @register.simple_tag 2 def page(filter_condtions,previous_orderby,search_text): 3 filters = "" 4 for k, v in filter_condtions.items(): 5 filters += "%s=%s" % (k, v) 6 ele = "%s&o=%s&_q=%s"%(filters,previous_orderby,search_text) 7 return mark_safe(ele) 8 return ""
2.搜索中的搜索框内显示正在搜索的数据的问题
1 return render(request, "king_admin/table_objs.html",{"admin_class":admin_class, 2 "query_sets":query_sets, 3 "filter_condtions":filter_condtions, 4 "orderby_key":orderby_key, 5 "previous_orderby":request.GET.get("o",""), 6 "search_text":request.GET.get("_q",""),} )
1 <input type="search" name="_q" class="form-control" style="margin: 10px 15px" value="{{ search_text }}" />
3.提示可以搜索的字段
1 <span>Search by 2 {% for column in admin_class.search_fields %} 3 {{ column }}, 4 {% endfor %} 5 </span>
7.动态跳转到数据修改页面
实现动态跳转到数据页,首先需要添加一个URL
re_path('(\w+)/(\w+)/(\d+)/change/', views.table_obj_change,name="table_obj_change"),
然后是views
1 def table_obj_change(request,app_name,table_name,obj_id): 2 print(request) 3 4 return render(request,"king_admin/table_obj_change.html")
接着是table_obj_change.html
1 {% extends "king_admin/table_index.html" %} 2 {% load tags %} 3 {% block container %} 4 5 table_chenge 6 7 {% endblock %}
最后就是添加数据页的第一列字段添加跳转的<a> 标签
1 @register.simple_tag 2 def bulid_table_row(request,obj,admin_class): 3 row_ele = "" 4 for index,column in enumerate(admin_class.list_display): 5 field_obj = obj._meta.get_field(column) 6 if field_obj.choices: 7 column_date = getattr(obj,"get_%s_display" % column)() 8 else: 9 column_date = getattr(obj,column) 10 11 if type(column_date).__name__ == "datetime": 12 column_date = column_date.strftime("%Y-%m-%d %H:%M:%S") 13 14 if index == 0: 15 column_date = "<a href='{request_path}{obj_id}/change/'>{date}</a>".format(request_path=request.path, 16 obj_id=obj.id,date=column_date) 17 18 row_ele += "<td>%s</td>" % column_date 19 20 return mark_safe(row_ele)
注意:一定要注意!!!!!!!
这个url的正则匹配是在django2.0上的
所以如果这样写
1 re_path('(\w+)/(\w+)/', views.display_table_objs, name="table_objs"), 2 re_path('(\w+)/(\w+)/(\d+)/change/', views.table_obj_change,name="table_obj_change"),
这样写是不会匹配成功的,上面的会一直匹配上面的url
所以应该这样写
1 re_path('(\w+)/(\w+)/(\d+)/change/', views.table_obj_change,name="table_obj_change"), 2 re_path('(\w+)/(\w+)/', views.display_table_objs, name="table_objs"),
8.动态生成Model Form
跳转到数据页就应该显示数据的基本内容
新建forms
1 from django.forms import forms,ModelForm 2 from crm import models 3 4 5 6 def create_model_form(request,admin_class): 7 8 class Meta: 9 model = admin_class.model 10 fields = "__all__" 11 attr = {"Meta":Meta} 12 _model_form_class = type("DynamicModelForm",(ModelForm,),attr) 13 14 return _model_form_class
1 from king_admin.forms import create_model_form 2 def table_obj_change(request,app_name,table_name,obj_id): 3 4 admin_class = king_admin.enabled_admins[app_name][table_name] 5 6 model_class_form = create_model_form(request,admin_class) 7 8 form_obj = model_class_form() 9 10 11 return render(request,"king_admin/table_obj_change.html",{"form_obj":form_obj})
显示效果:
优化model form的样式
1 from django.forms import forms,ModelForm 2 from crm import models 3 4 5 6 def create_model_form(request,admin_class): 7 8 def __new__(cls,*args,**kwargs): 9 for field_name,field_obj in cls.base_fields.items(): 10 field_obj.widget.attrs["class"] = "form-control" 11 12 return ModelForm.__new__(cls) 13 14 class Meta: 15 model = admin_class.model 16 fields = "__all__" 17 attr = {"Meta":Meta} 18 _model_form_class = type("DynamicModelForm",(ModelForm,),attr) 19 setattr(_model_form_class,"__new__",__new__) 20 21 return _model_form_class
1 def table_obj_change(request,app_name,table_name,obj_id): 2 3 admin_class = king_admin.enabled_admins[app_name][table_name] 4 model_class_form = create_model_form(request,admin_class) 5 6 obj = admin_class.model.objects.get(id=obj_id) 7 if request.method == "POST": 8 form_obj = model_class_form(request.POST,instance=obj) #更新 9 if form_obj.is_valid(): 10 form_obj.save() 11 else: 12 form_obj = model_class_form(instance=obj) 13 14 return render(request,"king_admin/table_obj_change.html",{"form_obj":form_obj})
1 {% extends "king_admin/table_index.html" %} 2 {% load tags %} 3 {% block container %} 4 5 <form class="form-horizontal" method="post"> 6 {% csrf_token %} 7 <span style="color: red">{{ form_obj.errors }}</span> 8 {% for field in form_obj %} 9 <div class="form-group"> 10 <label class="col-sm-2 control-label" style="font-weight: normal"> 11 {% if field.field.required %} 12 <b>{{ field.label }}:</b> 13 {% else %} 14 {{ field.label }}: 15 {% endif %} 16 </label> 17 <div class="col-sm-4"> 18 {{ field }} 19 </div> 20 </div> 21 {% endfor %} 22 23 <div> 24 <div class="col-lg-5"> 25 <button type="submit" class="btn btn-info pull-right" >保存</button> 26 </div> 27 </div> 28 </form> 29 30 {% endblock %}
9.添加客户信息表
首先在前段添加增加按钮
<div> <a href="{{ request.path }}add/"> <button class="btn btn-info pull-right" style="margin: 10px" >增加</button> </a> </div>
然后添加url
re_path('(\w+)/(\w+)/add/', views.table_obj_add,name="table_obj_add"),
1 def table_obj_add(request,app_name,table_name): 2 admin_class = king_admin.enabled_admins[app_name][table_name] 3 model_class_form = create_model_form(request, admin_class) 4 5 if request.method == "POST": 6 form_obj = model_class_form(request.POST) 7 if form_obj.is_valid(): 8 form_obj.save() 9 return redirect(request.path.replace("/add/","/")) 10 else: 11 form_obj = model_class_form() 12 13 return render(request, "king_admin/table_obj_add.html", {"form_obj": form_obj})
{% extends "king_admin/table_obj_change.html" %}
显示效果:
#####################################