项目一:CRM(客户关系管理系统)--6
Posted EagleSour
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目一:CRM(客户关系管理系统)--6相关的知识,希望对你有一定的参考价值。
功能是永远加不完的!重头戏的Action
放在后面作为压轴,接下来该添加三级页面啦!
1. 添加编辑页面轮廓
有的朋友可能会问:为何直接写编辑页面而没有写添加页面?那是因为二者是相互继承的关系,个人觉得先写编辑比较好,然后添加继承编辑页面,改动基本上后台数据的更新与存储的问题。
1.1. 原生admin路由分析
如图:
1.2. 构建编辑页面路由
在king_admin
应用下的urls.py
文件中添加:
1 from django.conf.urls import url 2 from king_admin import views 3 urlpatterns = [ 4 url(r\'^$\', views.index, name=\'table_index\'), 5 url(r\'^(\\w+)/(\\w+)/$\', views.display_objects, name=\'display_objects\'), 6 url(r\'^(\\w+)/(\\w+)/(\\d+)/edit/$\', views.table_object_edit,name="table_object_edit"), #添加该行数据 7 ]
1.3. 添加视图函数
在king_admin
应用下的views.py
文件中添加:
1 def table_object_edit(request, app_name, table_name, object_id): 2 return render(request, \'king_admin/table_object_edit.html\')
1.4. 添加模板文件
在template/king_admin/
目录下的table_object_edit.html
文件,并在文件中添加如下内容:
1 {% extends \'king_admin/table_index.html\' %} 2 {% block extra-css-resources %} 3 4 {% endblock %} 5 {% block container %} 6 7 {% endblock %}
1.5.添加编辑页面的入口
上面我们已经写完基本的页面流程,现在来添加编辑页面入口来打通整体流程,二级显示页面我们通过在templates
中进行编写,修改这里即可,只需要添加一个参数(request
),索引值和判断:
1 ... 2 3 <-----------------------创建表格行数据----------------------------- 4 @register.simple_tag 5 def create_row(request, query_set_obj, admin_class): 6 #创建标签元素--空,None不行 7 element = \'\' 8 9 #遍历要显示的models字段 10 for number, row in enumerate(admin_class.list_display): 11 #获取显示字段对应的字段对象 12 field_obj = admin_class.model._meta.get_field(row) 13 #获取数据 14 #判断choice 15 if field_obj.choices: 16 #通过反射获取对象里面的值,并执行该方法get_字段_display()获取choices里面的数值 17 row_data = getattr(query_set_obj, \'get_{0}_display\'.format(row))() 18 else: 19 row_data = getattr(query_set_obj, row) 20 21 #时间格式转换 22 if type(row_data).__name__ == \'datetime\': 23 row_data = row_data.strftime(\'%Y-%m-%d %H-%M-%S\') 24 25 #添加编辑页面入口 26 if number == 0: #add a tag, 可以跳转到修改页 27 row_data = "<a href=\'{request_path}{obj_id}/edit/\'>{data}</a>".format(request_path=request.path, 28 obj_id=query_set_obj.id, 29 data=row_data) 30 31 #标签元素的拼接 32 element += "<td>{0}</td>".format(row_data) 33 return mark_safe(element) 34 35 ...
上述内容改完后,不要忘记在模板文件中还要添加一个参数:request
。
访问看看:
2. 填充编辑页面详情
2.1. 编写动态生成ModelForm派生类的功能函数
由于数据量很大,每条数据都要进入到第三级页面中,生成新的页面进行操作:添加、修改、删除等。那么,我是不是要针对每条数据都要写一套代码,很显然是不可能的!作为程序员,重复代码就是最大的BUG
,尤其是大量的同样代码。
在三级页面中,不论是编辑、添加还是删除都有共通的地方。那么该怎么实现呢?好在Django
为我们提供了便捷的方式:动态生成Form
表单。
在Django
中,原生的admin
常结合models
使用的Form
表单功能是ModelForm
,它能够配合数据库动态生成数据表单。
我们知道如何动态的实现表单功能了,那它同样的问题就是代码的重复问题,那么多的数据,我们要写那么多的ModelForm
吗?回答是肯定的:不可能! 不想写重复代码其实也很简单的,我们只需要动态生成ModelForm
不就行了嘛!
通常我们使用ModelForm
会这样:
1 from django.forms import ModelForm 2 from crm import models 3 #要动态生成的目标类 4 class CustomerModelForm(ModelForm): 5 class Meta: 6 model = models.Customer 7 fields = "__all__"
现在,我们要让它自动创建:在king_admin
项目的目录下,创建forms.py
文件。
1 from django.forms import ModelForm 2 3 def create_model_form(request,admin_class): 4 \'\'\' 5 动态生成ModelForm类 6 :param request: 7 :param admin_class: 8 :return: 9 \'\'\' 10 <-----------------------类成员构造----------------------------- 11 class Meta: 12 model = admin_class.model 13 fields = "__all__" 14 #类的成员 15 attrs = {\'Meta\':Meta} 16 17 <-----------------------动态创建类----------------------------- 18 #type函数创建类--->type(\'类名\',(基类,),以字典形式的类的成员) 19 _model_form_class = type("DynamicModelForm",(ModelForm,),attrs) 20 21 <-----------------定义创建对象的方法----------------------------- 22 # 定义__new__方法,用于创建类,cls类名 23 def __new__(cls, *args, **kwargs): 24 # 遍历数据库的所有字段和字段对应的对象 25 for field_name, field_obj in cls.base_fields.items(): 26 # 为字段对象的组件添加class属性 27 field_obj.widget.attrs[\'class\'] = \'form-control\' 28 # 创建当前类的实例--->即创建子类 29 return ModelForm.__new__(cls) 30 # 定义元数据 31 32 <-------------------为对象添加属性-------------------------------- 33 #为该类添加__new__静态方法,当调用该类时,会先执行__new__方法,创建对象 34 # 这里会覆盖父类的__new__ 35 setattr(_model_form_class,\'__new__\',__new__) 36 37 return _model_form_class
2.2 编写视图函数
在二级显示页面中,我们通过点击id
值跳转到编辑页面,然后经过路由触发视图函数获取到相关数据,修改会经过上面创建的表单验证类进行验证:
1 ... 2 from king_admin.forms import create_model_form 3 4 ... 5 def table_object_edit(request, app_name, table_name, object_id): 6 admin_class = site.enabled_admins[app_name][table_name] 7 #创建ModelForm类 8 model_form = create_model_form(request, admin_class) 9 #通过id获取数据库内容 10 object_list = admin_class.model.objects.get(id=object_id) 11 12 if request.method == \'POST\': 13 #表单进行验证,更新数据 14 form_object = model_form(request.POST, instance=object_list) 15 if form_object.is_valid(): 16 form_object.save() 17 else: 18 form_object = model_form(instance=object_list) 19 20 return render(request, \'king_admin/table_object_edit.html\', {"form_object": form_object, 21 "admin_class": admin_class, 22 "app_name": app_name, 23 "table_name": table_name})
2.3 编写模板文件
在新建的table_object_edit.html
中我们添加的应该会比较多,因此,会拆分成几大部分编写。
2.3.1 基础字段内容显示
先将数据内容显示和字段名称显示出来:
1 {% extends \'king_admin/table_index.html\' %} 2 3 {% block extra-css-resources %} 4 5 {% endblock %} 6 7 8 {% block container %} 9 <form method="post" class="form-horizontal"> 10 {% csrf_token %} 11 {% for field in form_object %} 12 <div class="form-group" > 13 {# 显示名称 #} 14 <label class="col-sm-3 control-label" style="font-weight: normal"> 15 {{ field.label }} 16 </label> 17 {# 显示数据输入框 #} 18 <div class="col-lg-6" style="width: auto"> 19 {{ field }} 20 </div> 21 </div> 22 {% endfor %} 23 </form> 24 {% endblock %}
效果如下:
2.3.2 必填字段显示设置
效果我们看到了,已经达到预期。在回过头看看form_object
到底是什么?
在视图函数中,我们通过打印form_object
(自行添加print(form_object)
)能够看到如下内容:
1 <tr><th><label for="id_name">Name:</label></th><td><input class="form-control" id="id_name" maxlength="32" name="name" type="text" value="dfgh" /></td></tr> 2 <tr><th><label for="id_qq">Qq:</label></th><td><input class="form-control" id="id_qq" maxlength="64" name="qq" type="text" value="0002" required /></td></tr> 3 <tr><th><label for="id_qq_name">Qq name:</label></th><td><input class="form-control" id="id_qq_name" maxlength="64" name="qq_name" type="text" value="发电规划" /></td></tr> 4 <tr><th><label for="id_phone">Phone:</label></th><td><input class="form-control" id="id_phone" maxlength="64" name="phone" type="text" value="234蚊346" /></td></tr> 5 <tr><th><label for="id_source">Source:</label></th><td><select class="form-control" id="id_source" name="source" required> 6 <option value="">---------</option> 7 <option value="0" selected="selected">转介绍</option> 8 <option value="1">QQ群</option> 9 <option value="2">官网</option> 10 <option value="3">百度推广</option> 11 <option value="4">51CTO</option> 12 <option value="5">知乎</option> 13 <option value="6">市场推广</option> 14 </select></td></tr> 15 <tr><th><label for="id_referral_from">转介绍人qq:</label></th><td><input class="form-control" id="id_referral_from" maxlength="64" name="referral_from" type="text" value="567456" /></td></tr> 16 <tr><th><label for="id_consult_course">咨询课程:</label></th><td><select class="form-control" id="id_consult_course" name="consult_course" required> 17 <option value="">---------</option> 18 <option value="4">成功学</option> 19 <option value="5">搜索引擎</option> 20 <option value="6" selected="selected">内核开发</option> 21 <option value="7">相亲</option> 22 </select></td></tr> 23 <tr><th><label for="id_content">咨询详情:</label></th><td><textarea class="form-control" cols="40" id="id_content" name="content" rows="10" required> 24 如图</textarea></td></tr> 25 <tr><th><label for="id_tags">Tags:</label></th><td><select multiple="multiple" class="form-control" id="id_tags" name="tags"> 26 <option value="3" selected="selected">大牛</option> 27 </select></td></tr> 28 <tr><th><label for="id_status">Status:</label></th><td><select class="form-control" id="id_status" name="status" required> 29 <option value="0">已报名</option> 30 <option value="1" selected="selected">未报名</option> 31 </select></td></tr> 32 <tr><th><label for="id_consultant">Consultant:</label></th><td><select class="form-control" id="id_consultant" name="consultant" required> 33 <option value="">---------</option> 34 <option value="1" selected="selected">三弗</option> 35 </select></td></tr> 36 <tr><th><label for="id_memo">Memo:</label></th><td><textarea class="form-control" cols="40" id="id_memo" name="memo" rows="10"> 37 如图用户</textarea></td></tr>
细心的朋友会发现一个required
,也会问这是什么鬼?哪来的?其实回头看看打印内容目的就是要看这个required
属性。
在独立使用Form
表单时,我们可以独立设置相关字段的参数,同样在MoldelForm
中也是可以的,但是有一点是值得注意的: If the model field has blank=True, then required is set to False on the form field. Otherwise, required=True.
这是官方的原话。意思是:如果在model中字段参数中设置了blank=True
,那么Form
中的required=False
;若没设置blank=True
,则默认为required=True
(具体看源码的初始化函数设定)。
现在,明白了required
是怎么来的了吧!好了,开始该处理它了,只需要我们在模板文件中添加一个简单的判断和样式修饰:
1 {# 显示名称 #} 2 {% if field.field.required %} 3 <label class="col-sm-3 control-label" style="font-weight: normal"> 4 <span style="color: red">*</span>{{ field.label }} 5 </label> 6 {% else %} 7 <label class="col-sm-3 control-label" style="font-weight: normal"> 8 {{ field.label }} 9 </label> 10 {% endif %}
渲染后的效果:
2.3.3 添加保存按钮
基本的显示字段和样式添加的差不多了,接下来就是添加提交的按钮(保存)。在同一个form
表单中添加如下:
1 ... 2 3以上是关于项目一:CRM(客户关系管理系统)--6的主要内容,如果未能解决你的问题,请参考以下文章
Django项目:CRM(客户关系管理系统)--83--73PerfectCRM实现CRM模板统一
Django项目:CRM(客户关系管理系统)--45--36PerfectCRM实现CRM用户登陆注销02