参考:https://www.cnblogs.com/Eric15/articles/9247723.html
kingadmin页面开发基于CRM开发,详情请参考上述链接
Kingadmin
前戏:目录
在CRM项目中:
01. 创建Kingadmin App:python manage.py startapp kingadmin
02. 创建static静态文件夹、templates文件夹,将需要的样式表、html页面分别移入static、templates文件夹中
03. perfect CRM中的setting设置:
INSTALLED_APPS:添加 “kingadmin” APP
TEMPLATES:添加 “kingadmin/templates” 路径
STATICFILES_DIRS:添加 “static” 路径
kingadmin 操作开始
1、kingadmin下的login、logout界面,参考crm写就可以了,需要注意的是:
kingadmin中创建urls.py文件,操作:
# perfect CRM下的urls: path('kingadmin/',include("kingadmin.urls")), # kingadmin下的urls: (urls.py需创建) from django.urls import path from kingadmin import views urlpatterns = [ path('login/',views.acc_login), path('logout/',views.acc_logout,name='logout'), ]
2、kingadmin下的首页:
urls:
1 re_path('^$',views.app_index,name='app_index'),
views:
1 def app_index(request): 2 """kingadmin下的首页""" 3 return render(request,"kingadmin/app_index.html")
html:app_index.html
1 #继承于kingadmin下的index.html 2 3 {% extends "index.html" %} 4 5 {% block right-content-container %} 6 {% block Role_name %} 7 KingAdmin 8 {% endblock %} 9 {% endblock %}
3、kingadmin下的主页(类似admin主页)
(1) settings中需添加app:
(2) 生成app_setup.py文件:用于导入并执行各app下的kingadmin.py文件,如无kingadmin.py文件则跳过
1 from django import conf 2 3 def kingadmin_auto_discover(): 4 for app_name in conf.settings.INSTALLED_APPS: 5 # 遍历setting配置中的各app,找到app下的'kingadmin.py',如有,则导入,如没有则报错:ImportError 6 # mod = importlib.import_module(app_name, 'kingadmin') 7 try: 8 #try 找到各APP中的Kingadmin.py文件,没找到的pass处理 __import__ 等价于 importlib.import_module(app_name, 'kingadmin') 9 mod =__import__("%s.kingadmin"%app_name) 10 # print(mod.kingadmin) # <module 'crm.kingadmin' from 'C:\\Users\\Administrator\\Desktop\\PerfectCRM\\crm\\kingadmin.py'> 11 12 except ImportError: 13 pass
(3) 自创建kingadmin注册文件:sites.py
1 from kingadmin.admin_base import BaseKingAdmin 2 # BaseKingAdmi需另外创建 3 4 class AdminSite(object): 5 def __init__(self): 6 self.enabled_admin = {} 7 8 9 def register(self,model_class,admin_class=None): 10 """ 11 注册表: 12 site.register(models.CustomerInfo,CustomerAdmin) 13 :param model_class: models.CustomerInfo 14 :param admin_class: CustomerAdmin 15 model_class._meta.app_label = models.CustomerInfo._meta.app_label :获取对应APP名称 16 model_class._meta.model_name = models.CustomerInfo._meta.model_name :获取对应表名称 17 """ 18 19 app_name = model_class._meta.app_label 20 model_name = model_class._meta.model_name 21 22 if not admin_class: # 为了避免多个model共享同一个BaseKingAdmin内存对象 23 # 实例化BaseKingAdmin对象,每一次循环此语句都开辟一块新内存 24 admin_class = BaseKingAdmin() 25 26 else: 27 # 实例化 CustomerAdmin 对象 28 admin_class = admin_class() 29 30 admin_class.model = model_class # 把model_class赋值给了admin_class 31 32 if app_name not in self.enabled_admin: 33 self.enabled_admin[app_name] = {} 34 35 # enabled_admins中存的是字典(字典中套字典):crm:{ {'CustomerInfo':'CustomerAdmin'} , {'Role':'RoleAdmin'}} 36 # enabled_admins[crm][CustomerInfo] = CustomerAdmin 37 self.enabled_admin[app_name][model_name] = admin_class 38 39 40 site = AdminSite()
BaseKingAdmin:
1 class BaseKingAdmin(object): 2 pass
(4) 在各app中创建kingadmin.py文件:用于自定义kingadmin注册
1 from kingadmin.sites import site 2 from crm import models 3 from kingadmin.admin_base import BaseKingAdmin 4 5 6 print("crm kingadmin ...........") 7 8 class CustomerAdmin(BaseKingAdmin): 9 list_display = ['id','name','source','contact_type','contact','consultant','consult_content','status','date'] 10 list_filter = ['source','consultant','status','date'] 11 search_fields = ['contact','consultant__name'] 12 # 13 # readonly_fields = ['status', 'contact'] 14 # filter_horizontal = ['consult_courses', ] 15 # 16 # actions = ['change_status', ] 17 18 # def change_status(self, request, querysets): 19 # # print("kingadmin action:", self, request, querysets) 20 # querysets.update(status=1) 21 22 23 # class CourseRecordAdmin(BaseKingAdmin): 24 # actions = ['change_status', ] 25 26 site.register(models.CustomerInfo,CustomerAdmin) 27 site.register(models.Role) 28 site.register(models.Menus) 29 site.register(models.Course) 30 site.register(models.ClassList) 31 # site.register(models.CourseRecord,CourseRecordAdmin) 32 site.register(models.StudyRecord) 33 site.register(models.UserProfile)
(5)views:
1 from kingadmin import app_setup 2 from kingadmin.sites import site 3 4 #导入各app中的kingadmin模块 5 app_setup.kingadmin_auto_discover()
(6) 页面app_index.html:
1 {% extends 'kingadmin/index.html' %} 2 3 4 {% block right-content-container %} 5 <h2 class="page-header">Kingadmin</h2> 6 <div> 7 <!-- 各APP及其表数据展示(body部分的右边展示栏)--> 8 {% for app_name,app_tables in site.enabled_admins.items %} 9 <table class="table table-striped table-hover"> 10 <thead> 11 <tr> 12 <th>{{ app_name }}</th> 13 </tr> 14 </thead> 15 <tbody> 16 {% for model_name in app_tables %} 17 <tr> 18 <td><a href="{% url 'table_obj_list' app_name model_name %}">{{ model_name }}</a></td> 19 <td><a href="/kingadmin/{{ app_name }}/{{ model_name }}/add"><span class="glyphicon glyphicon-plus" aria-hidden="true" style="margin-right: 5px"></span>Add</a></td> 20 <td><a href="/kingadmin/{{ app_name }}/{{ model_name }}"><span class="glyphicon glyphicon-pencil" aria-hidden="true" style="margin-right: 5px"></span>Change</a></td> 21 </tr> 22 {% endfor %} 23 </tbody> 24 25 26 </table> 27 28 29 30 {% endfor %} 31 32 </div> 33 34 35 36 37 38 39 40 {% endblock %}
3、进入crm APP中的customerinfo表中,列出list_display中的数据 及过滤功能:
(1)在主页app_index.html设置可点击超链接
(2) 开发数据列表页:当用户点击crm下的customerinfo时,进入customerinfo数据页
1. table_obj_list.html:
1 {#显示表中各数据#} 2 <table class="table table-striped"> 3 <thead> 4 <tr> 5 {% for column in admin_class.list_display %} 6 <th>{{ column }}</th> 7 8 {% endfor %} 9 10 </tr> 11 </thead> 12 <tbody> 13 {% for obj in querysets %} 14 <tr> 15 {# <td><input row-select="true" type="checkbox" value="{{ obj.id }}"></td>#} 16 {% build_table_row obj admin_class %} 17 </tr> 18 {% endfor %} 19 </tbody> 20 21 22 </table>
2. 自定义模板标签:
1 """ 2 templatetags包,用于创建自定义标签,再用于前端显示 3 自定义标签步骤: 1、在APP文件中创建 templatetags包(不是文件夹) 4 2、在templatetags包中创建 kingadmin.py文件 5 3、导入:from django.template import Library 6 4、实例化:register = Library() 。注:命名必须‘register’,不能改 7 """
(3) 关于过滤、搜索、排序、分页等功能请点击下述链接↓:
https://www.cnblogs.com/Eric15/articles/9270586.html
5、 kingadmin下的增删改查:
5-1. 查看 / 修改操作:
urls:
1 re_path(r'^(\w+)/(\w+)/(\d+)/change/$',views.table_obj_change,name='table_obj_change'),
views:
1 @login_required 2 def table_obj_change(request,app_name,model_name,obj_id): 3 """ 4 信息修改操作(页面) 5 利用Django自带form表单操作 6 """ 7 admin_class = site.enabled_admins[app_name][model_name] 8 model_form = form_handle.create_dynamic_model_form(admin_class) 9 obj = admin_class.model.objects.get(id=obj_id) 10 if request.method == 'GET': 11 # GET:查看当前页,返回当前对象的所有数据 12 form_obj = model_form(instance=obj) 13 else: 14 # POST: 修改当前页,获取数据并保存新数据 15 form_obj = model_form(instance=obj, data=request.POST) 16 if form_obj.is_valid(): 17 form_obj.save() 18 return redirect("/kingadmin/%s/%s/" % (app_name, model_name)) 19 # print("type--------------",type(form_obj)) 20 return render(request, 'kingadmin/table_obj_change.html', locals())
自定义form表单接收/返回数据(Django自带Form表单):与新增操作共享
1 """ 2 动态生成form表单,动态展示各表中单个角色内的详细表单信息 3 接收后台数据,根据数据返回或保存数据 4 """ 5 6 7 from django.forms import ModelForm 8 9 10 def create_dynamic_model_form(admin_class,form_add=False): 11 """ 12 根据传入admin_class,获取不同表信息,动态生成对应的modelform表单 13 form_add: False 默认是修改的表单,True时为添加 14 """ 15 16 class Meta: 17 model = admin_class.model 18 #所有字段都展示 19 fields = "__all__" 20 if not form_add:#change,如果是修改操作,不能修改的信息应该设置成只读项 21 exclude = admin_class.readonly_fields 22 admin_class.form_add = False #这是因为自始至终admin_class实例都是同一个, 23 # 这里修改属性为True是为了避免上一次添加调用将其改为了True 24 else: #add,如果是添加操作,没有只读项这回事 25 admin_class.form_add = True#返回给前端,判断是修改数据还是新增数据 26 27 28 def __new__(cls,*args,**kwargs): 29 """ 30 Django中ModelForm表单生成都是在ModelForm的__new__方法中生成 31 要给通过ModelForm生成的表单添加自定义标签样式,需要在此方法中处理 32 base_fields----: 表单中所有信息,([('名称',对象),('名称',对象)...])OrderedDict([('name', <django.forms.fields.CharField object at 0x0000000004ACA4A8>), ('contact_type', <django.forms.fields.TypedChoiceField object at 0x0000000004ACA5C0>).... 33 """ 34 for field_name in cls.base_fields: #获得每个字段的名称 35 # print('base_fields----:',cls.base_fields) 36 field_obj =cls.base_fields[field_name] #获取该字段名对应的对象 37 # 给该字段对象更新/增加class属性 38 field_obj.widget.attrs.update({'class':'form-control'}) 39 40 # 最后务必调用父类__new__方法 41 return ModelForm.__new__(cls) 42 43 44 45 dynamic_form = type("DynamicModelForm",(ModelForm,),{'Meta':Meta,'__new__':__new__}) 46 """ 47 type("DynamicModelForm",(ModelForm,) 48 DynamicModelForm:类名 49 ModelForm:继承的类 50 {'Meta':Meta}:DynamicModelForm类的成员,可以是类、方法或其他 51 """ 52 return dynamic_form #dynamic_form:是类,返回dynamic_form类 <class 'django.forms.widgets.DynamicModelForm'>
模板页面:内容继承于:kingadmin/table_obj_change_component.html 页面
1 {% extends 'kingadmin/index.html' %} 2 {% load kingadmin_tags %} 3 4 5 {% block right-content-container %} 6 {# <ol class="breadcrumb">#} 7 {# <li><a href="/kingadmin/">Home</a></li>#} 8 {# <li><a href="/kingadmin/{{ app_name }}">{{ app_name }}</a></li>#} 9 {# <li><a href="/kingadmin/{{ app_name }}/{{ model_name }}/">{% get_model_verbose_name admin_class %}</a></li>#} 10 {# <li class="active">{{ form_obj.instance }}</li>#} 11 {# </ol>#} 12 <h2 class="page-header">{% get_model_name admin_class %}</h2> 13 <h4 class="page-header">更改 {{ form_obj.instance }} 信息:</h4> 14 15 <div> 16 17 {% include 'kingadmin/table_obj_change_component.html' %} 18 19 </div> 20 21 {% endblock %}
kingadmin/table_obj_change_component.html:用于修改或增加数据时,前端显示内容
1 {% load kingadmin_tags %} 2 3 4 <form class="form-horizontal" method="post"> {% csrf_token %} 5 {{ form_obj.errors }} 6 {% for field in form_obj %} 7 <div class="form-group"> 8 <label class="col-sm-2 control-label">{{ field.label }}:</label> 9 <div class="col-sm-10 "> 10 {{ field }} 11 <span style="color: red">{{ field.errors.0 }} </span> 12 </div> 13 </div> 14 {% endfor %} 15 16 17 {% if not admin_class.form_add %} <!--如果这是修改表单--> 18 {% for field in admin_class.readonly_fields %} 19 <div class="form-group"> 20 <label class="col-sm-2 control-label">{{ field }}:</label> 21 <div class="col-sm-10"> 22 <p style="margin-top: 7px">{% get_obj_field_val form_obj field %}</p> 23 </div> 24 </div> 25 {% endfor %} 26 {% endif %} 27 28 <div class="col-sm-offset-11 col-sm-2"> 29 <button type="submit" class="btn btn-info">Save</button> 30 </div> 31 32 </form>
查看 / 修改页面:
5-2. 新增操作:
urls:
1 re_path(r'^(\w+)/(\w+)/add/$',views.table_obj_add,name='table_obj_add'),
views:
1 @login_required 2 def table_obj_add(request,app_name,model_name): 3 """增加操作(页面)""" 4 admin_class = site.enabled_admins[app_name][model_name] 5 model_form = form_handle.create_dynamic_model_form(admin_class,form_add=True) 6 if request.method == 'GET': 7 # GET:查看当前页,返回当前对象的所有数据 8 form_obj = model_form() 9 else: 10 # POST: 修改当前页,获取数据并保存新数据 11 form_obj = model_form(data=request.POST) 12 if form_obj.is_valid(): 13 form_obj.save() 14 return redirect("/kingadmin/%s/%s/" % (app_name, model_name)) 15 16 return render(request, 'kingadmin/table_obj_add.html', locals())
自定义form表单接收/返回数据(Django自带Form表单):同查看操作
模板页面:内容继承于:kingadmin/table_obj_change_component.html 页面
1 {% extends 'kingadmin/index.html' %} 2 {% load kingadmin_tags %} 3 4 5 {% block right-content-container %} 6 {# <ol class="breadcrumb">#} 7 {# <li><a href="/kingadmin/">Home</a></li>#} 8 {# <li><a href="/kingadmin/{{ app_name }}">{{ app_name }}</a></li>#} 9 {# <li><a href="/kingadmin/{{ app_name }}/{{ model_name }}/">{% get_model_verbose_name admin_class %}</a></li>#} 10 {# <li class="active">{{ form_obj.instance }}</li>#} 11 {# </ol>#} 12 <h2 class="page-header">{% get_model_name admin_class %}</h2> 13 <h4 class="page-header">添加新客户信息:</h4> 14 dsggdh 15 <div> 16 17 {% include 'kingadmin/table_obj_change_component.html' %} 18 19 </div> 20 21 {% endblock %}
新增页面:
PS:新增/修改操作下,关于多对多选择的操作,题中:咨询课程
关键词:kingadmin.py → class CustomerAdmin(BaseKingAdmin) 下的:filter_horizontal = ['consult_courses', ]
效果图:
模板HTML页面:
1 <div class="col-sm-10"> 2 {% if field.name in admin_class.filter_horizontal %} 3 <div class="col-lg-5 panel-default "> 4 <div class="panel-heading">课程咨询 :</div> 5 <div class="input-group"> 6 <span class="glyphicon glyphicon-search input-group-addon"></span> 7 8 <input type="search" class="form-control panel-body" oninput="FuzzSearch(this)"> 9 {# <span class="glyphicon glyphicon-search input-group-addon"></span>#} 10 </div> 11 <select id="id_{{ field.name }}_from" multiple class="form-control panel-body selecting" style="height: 116px;"> 12 {% get_available_m2m_data field.name form_obj admin_class as available_m2m_data %} 13 {% for obj in available_m2m_data %} 14 <option ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')" 15 value="{{ obj.id }}">{{ obj }}</option> 16 {% endfor %} 17 </select> 18 <p><a onclick="MoveAllElements('id_{{ field.name }}_from','id_{{ field.name }}_to')">Choose 19 All</a></p> 20 </div> 21 <div class="col-lg-5 panel-default"> 22 <div class="panel-heading">选中的课程 :</div> 23 <select tag="selected_m2m" id="id_{{ field.name }}_to" multiple class="form-control" 24 name="{{ field.name }}" style="height: 150px;"> 25 {% get_selected_m2m_data field.name form_obj admin_class as selected_m2m_data %} 26 {% for obj in selected_m2m_data %} 27 <option value="{{ obj.id }}" 28 ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_from')">{{ obj }}</option> 29 {% endfor %} 30 31 </select> 32 <p><a onclick="MoveAllElements('id_{{ field.name }}_to','id_{{ field.name }}_from')">Remove 33 All</a></p> 34 </div> 35 {% else %} 36 {{ field }} 37 {% endif %} 38 <span style="color: red">{{ field.errors.0 }} </span> 39 </div>
模板HTML下的js操作:
function MoveSelectedOption(ele, target_id) :多选框内,双击内容实现左移右移
function MoveAllElements(from_id, to_id) :点击 ‘Choose All‘ 或 ‘Remove All’ ,实现数据全部左移或右移
function FuzzSearch(ele) :模糊查询
function FuzzSearch(ele) :当页面数据提交时,让‘选中的课程’处于已选状态,默认未选中,无此方法会报错(‘未填写数据’)
1 function MoveSelectedOption(ele, target_id) { 2 #左移右移 3 4 var new_target_id = $(ele).parent().attr('id'); 5 <!--获得父类select的id值--> 6 var option = "<option value='" + $(ele).val() + "'ondblclick=MoveSelectedOption(this,'" + new_target_id + "') >" + $(ele).text() + "</option>"; 7 $("#" + target_id).append(option); 8 $(ele).remove(); 9 10 }
1 function MoveAllElements(from_id, to_id) { 2 #all左移或右移 3 4 {#console.log( $("#"+from_id).children())#} 5 $("#" + from_id).children().each(function () { <!--拿到select下的子类option,循环option执行函数--> 6 MoveSelectedOption(this, to_id); 7 }) 8 }
1 function FuzzSearch(ele) { <!--模糊查询--> 2 3 {#console.log($(ele).val())#} 4 var search_text = $(ele).val().toUpperCase(); 5 <!--拿到搜索框中输入的文本(转大写形式)--> 6 7 $('.selecting').children().each(function () { 8 if ($(this).text().toUpperCase().search(search_text) != -1) { 9 $(this).show(); 10 } else { 11 $(this).hide(); 12 } 13 }); 14 15 }
1 function VerificationBeforeFormSubmit() { 2 <!--提交信息前,让select框中数据全选--> 3 4 $("select[tag] option").prop('selected', true); 5 6 }
自定义tag标签生成:kingadmin_tags.py
get_available_m2m_data :返回的是m2m字段关联表的所有数据
1 @register.simple_tag 2 def get_available_m2m_data(field_name,form_obj,admin_class): 3 """ 4 返回的是m2m字段关联表的所有数据 5 filter_horizontal = ['consult_courses', ] 6 field_obj:拿到consult_courses字段的对象(一个对象) 7 field_obj.related_model:拿到consult_courses关联的表对象 8 field_obj.related_model.objects.all():获取关联表的所有数据(queryset对象,打印课程名称) 9 set():集合 10 """ 11 12 field_obj = admin_class.model._meta.get_field(field_name) 13 # print("field_obj----:",field_obj) 14 obj_list = set(field_obj.related_model.objects.all()) 15 # obj_list = field_obj.related_model.objects.all() 16 17 if form_obj.instance.id: 18 selected_data = set(getattr(form_obj.instance ,field_name).all()) 19 20 return obj_list - selected_data 21 else: 22 return obj_list
get_selected_m2m_data:返回已选的m2m数据
1 @register.simple_tag 2 def get_selected_m2m_data(field_name,form_obj,admin_class): 3 """ 4 返回已选的m2m数据 5 getattr(form_obj.instance ,field_name):field_name=consult_courses, getattr('对象','名称'),名称如果是外键,则获得该对象中外键对应 6 的表对象 7 getattr(form_obj.instance ,field_name).all():获取该外键关联表内(属于该对象的)所有数据 8 """ 9 10 if form_obj.instance.id: 11 selected_data = getattr(form_obj.instance ,field_name).all() 12 13 return selected_data 14 15 else: 16 return []
5-3、删除操作
urls:
1 re_path(r'^(\w+)/(\w+)/(\d+)/delete/$', views.table_obj_delete, name="obj_delete"),
views:
1 @login_required 2 def table_obj_delete(request,app_name,model_name,obj_id): 3 """删除操作""" 4 admin_class = site.enabled_admins[app_name][model_name] 5 obj = admin_class.model.objects.get(id=obj_id) 6 if request.method == "POST": 7 obj.delete() 8 return redirect("/kingadmin/{app_name}/{model_name}/".format(app_name=app_name,model_name=model_name)) 9 return render(request,'kingadmin/table_obj_delete.html',locals())
模板HTML页面:
1 {% extends 'kingadmin/index.html' %} 2 {% load kingadmin_tags %} 3 4 {% block right-content-container %} 5 6 7 <h4 class="page-header alert-danger">注意:以下与{{ obj }}相关联的数据都将被删除!</h4> 8 9 <div> 10 11 12 13 14 {% display_all_related_objs obj as all_related_obj_eles %} 15 {{ all_related_obj_eles|safe }} 16 17 18 19 <form method="post">{% csrf_token %} 20 21 <input type="submit" class="btn btn-danger" value="确认删除"> 22 23 24 <a href="/kingadmin/{{ app_name }}/{{ model_name }}/{{ obj_id }}/change" class="btn btn-info" >返回</a> 25 26 </form> 27 28 </div> 29 30 {% endblock %}
母模板:table_obj_change_component.html
1 # table_obj_change_component.html下添加下列数据: 2 3 {% if form_obj.instance.id %} 4 <div class="col-sm-2"> 5 <a class="btn btn-danger" href="{% url 'obj_delete' app_name model_name form_obj.instance.id %}">Delete</a> 6 7 </div> 8 {% endif %}
自定义tag标签:kingadmin_tags.py:
def display_all_related_objs:显示要被删除对象的所有关联对象
1 # 删除操作 2 @register.simple_tag 3 def display_all_related_objs(obj): 4 """ 5 显示要被删除对象的所有关联对象 6 :param obj: 7 :return: 8 """ 9 ele = "<ul><b style='color:red'>%s</b>" % obj 10 # ele += "<li><a href='/kingadmin/%s/%s/%s/change/'>%s</a></li>" %(obj._meta.app_label, 11 # obj._meta.model_name, 12 # obj.id,obj) 13 """ 14 obj = admin_class.model.objects.get(id=obj_id) 15 obj._meta.related_objects:拿到obj被关联的所有一对一、多对一、多对多的表[ManyToMany、ManyToOne],多对一是指己方表被别的表关联 16 reversed_fk_obj.name:拿到主动关联表的表名(含有fk外键关联的) 17 getattr(obj,related_lookup_key).all() :getattr(obj,Role_set).all(),反向查关联表的所有关联的数据[queryset集合] 18 reversed_fk_obj.get_internal_type():判断表类型,ForeignKey、ManyToManyField 19 getattr(obj,related_lookup_key).all()= obj.Role_set.all() 20 """ 21 22 for reversed_fk_obj in obj._meta.related_objects: 23 24 if reversed_fk_obj.get_internal_type() == "OneToOneField": # 一对一或者一对多不需要操作,多对一、多对多需要下述操作 25 continue 26 else: 27 related_table_name = reversed_fk_obj.name 28 related_lookup_key = "%s_set" % related_table_name 29 related_objs = getattr(obj,related_lookup_key).all() #反向查所有关联的数据 30 ele += "<li>%s<ul> "% related_table_name 31 32 # if reversed_fk_obj.get_internal_type() == "OneToOneField": # 一对一或者一对多不需要操作,多对一、多对多需要下述操作 33 34 35 if reversed_fk_obj.get_internal_type() == "ManyToManyField": # 不需要深入查找 36 for i in related_objs: 37 ele += "<li><a href='/kingadmin/%s/%s/%s/change/'>%s</a> 记录里与[%s]相关的的数据将被删除</li>" \ 38 % (i._meta.app_label,i._meta.model_name,i.id,i,obj) 39 else: 40 for i in related_objs: 41 #ele += "<li>%s--</li>" %i 42 ele += "<li><a href='/kingadmin/%s/%s/%s/change/'>%s</a></li>" %(i._meta.app_label, 43 i._meta.model_name, 44 i.id,i) 45 ele += display_all_related_objs(i) 46 47 ele += "</ul></li>" 48 49 ele += "</ul>" 50 51 return ele
5-4、kingadmin下的action功能开发:
kingadmin.py:自定义action方法:处理选中的数据
1 # 添加至:class CustomerAdmin(BaseKingAdmin)中 2 actions = ['change_status', ] 3 4 def change_status(self, request, querysets): 5 # print("kingadmin action: TEST……", self, request, querysets) 6 print("kingadmin action: 更改选中数据状态!") 7 # querysets.update(status=1)
admin_base.py:自定义action方法:批量删除操作
1 class BaseKingAdmin(object): 2 def __init__(self): 3 self.actions.extend(self.default_actions) 4 5 default_actions = ['delete_selected_objs'] 6 actions = [] 7 8 9 def delete_selected_objs(self, request, querysets): 10 11 print("action:这是删除操作,请谨慎处理!")
views:
在table_obj_list函数中添加下列内容:映射上述自定义方法
1 # 用于kingadmin下action行为所做操作 2 if request.method == "POST": 3 # print(request.POST) 4 selected_action = request.POST.get('action') 5 selected_ids = json.loads(request.POST.get('selected_ids')) 6 # print(selected_action,selected_ids) 7 if not selected_action: # 如果有action参数,代表这是一个正常的action,如果没有,代表可能是一个删除动作 8 if selected_ids: # 这些选中的数据都要被删除 9 admin_class.model.objects.filter(id__in=selected_ids).delete() 10 else: # 走action流程 11 selected_objs = admin_class.model.objects.filter(id__in=selected_ids) 12 13 admin_action_func = getattr(admin_class, selected_action) 14 response = admin_action_func(request, selected_objs) 15 # response = admin_action_func(request,selected_objs) 16 if response: 17 return response
模板HTML页面:
在table_obj_list.html中某个位置添加下列代码:
1 {# kingadmin action 操作 #} 2 <form onsubmit="return ActionCheck(this)" method="post">{% csrf_token %} 3 <div class="row" style="margin-top:5px"> 4 <div class="col-lg-3"> 5 <select class="form-control" name="action" > 6 <option value="">---------</option> 7 {% for action in admin_class.actions %} 8 <option value="{{ action }}">{{ action }}</option> 9 {% endfor %} 10 </select> 11 </div> 12 <div> 13 <input type="submit" value="GO" style="margin-top: 4px"> 14 15 </div> 16 </div> 17 18 </form>
在table_obj_list.html中最后添加下列js操作:
function SelectAllObjs(ele):点击全选或全不选
1 function SelectAllObjs(ele) { 2 3 if ($(ele).prop('checked')){ 4 $('input[row-select]').prop('checked',true) 5 6 }else { 7 $('input[row-select]').prop('checked',false) 8 }
function ActionCheck(ele):获取数据后生成标签提供给后台使用
1 function ActionCheck(ele){ 2 var selected_action = $("select[name='action']").val(); 3 var selected_objs = $("input[row-select]").filter(":checked");//找到已选数据(一条或多条) 4 {#console.log($("select[name='action']").val())#} 5 if (!selected_action){ //action框未选择方法 6 alert("no action selected!"); 7 return false 8 } 9 if (selected_objs.length == 0 ){ //没有选中数据 10 alert("no object selected!"); 11 return false 12 }else { 13 //生成一个标签,放到form里 14 15 var selected_ids = []; 16 $.each(selected_objs,function () { //循环selected_objs数据 17 console.log($(this) ); 18 selected_ids.push($(this).val()) 19 }); 20 console.log(selected_ids); 21 var input_ele = "<input type='hidden' name='selected_ids' value=" + JSON.stringify(selected_ids) + ">" 22 23 $(ele).append(input_ele); 24 }