项目一:CRM(客户关系管理系统)--8

添加、修改页面都已经搞定,就差删除功能啦!删除这里就比较麻烦了,麻烦在那些表之间的关系。

1. 添加删除功能

1.1 删除页面路由

为用户的良好体验,我们新增加一个删除显示页面,路由:

1 urlpatterns = [
2     url(r‘^$‘, views.index, name=‘table_index‘),
3     url(r‘^(\w+)/(\w+)/$‘, views.display_objects, name=‘display_objects‘),
4     url(r‘^(\w+)/(\w+)/(\d+)/edit/$‘, views.table_object_edit,name="table_object_edit"),
5     url(r‘^(\w+)/(\w+)/add/$‘, views.table_object_add,name="table_object_add"),
6     url(r‘^(\w+)/(\w+)/(\d+)/delete/$‘, views.table_object_delete,name="table_object_delete"),#删除路由
7 ]

1.2 添加删除页面模板

templates/king_admin目录下新建table_object_delete.html文件,内容如下:

 1 {% extends ‘king_admin/table_index.html‘ %}
 2
 3 {% block body-content %}
 4
 5     {# 表单提交  #}
 6     <form method="post">
 7         {% csrf_token %}
 8         <input type="submit" class="btn btn-danger" value="Yes,I‘m sure">
 9         <input type="hidden" value="yes" name="delete_confirm">
10         <a class="btn btn-info" href="{% url ‘king_admin:table_object_edit‘ app_name table_name object_id %}">No,Take me back</a>
11     </form>
12 {% endblock %}

1.3 视图函数

 1 def table_object_delete(request, app_name, table_name, object_id):
 2     admin_class = site.enabled_admins[app_name][table_name]
 3
 4     object_list = admin_class.model.objects.filter(id=object_id)
 5     if request.method == ‘POST‘:
 6         if request.POST.get(‘delete_confirm‘) == ‘yes‘:
 7             object_list.delete()
 8             return redirect(‘/king_admin/{app_name}/{table_name}‘.format(app_name=app_name, table_name=table_name))
 9
10
11     return render(request, ‘king_admin/table_object_delete.html‘, {‘app_name‘: app_name,
12                                                                    ‘table_name‘: table_name,
13                                                                    ‘object_id‘: object_id,
14                                                                    ‘object_list‘: object_list})

1.4 为删除页面添加入口

table_object_edit.html文件中,只需要添加一个按钮,但是这个按钮很是关键 ,要经过一些特别的处理,避免一些不必要的问题发生。

 1 ...
 2
 3         {% endfor %}
 4     {# 添加保存按钮 #}
 5      <div class="form-group">
 6          {# 添加删除功能,并独立出来,以免影响其他功能 #}
 7          {% block obj_delete %}
 8           <div class="col-sm-2">
 9                 <a class="btn btn-danger" href="{% url ‘king_admin:table_object_delete‘ app_name table_name object_id %}">删除</a>
10           </div>
11           {% endblock %}
12           <div class="col-sm-10 ">
13             <button type="submit" class="btn btn-success pull-right">保存</button>
14           </div>
15       </div>
16     </form>
17
18 ...

还记得,我们的添加功能是继承自编辑页面吧,那里同样也要加上继承标签,以免二者出现一些关联错误。

table_object_add.html页面添加一个块标签即可,且不加任何内容:

1 ...
2
3 {% block obj_delete %}
4
5 {% endblock %}

渲染后的效果:

删除后跳转到显示页面的功能在视图函数中已经写好,不在赘述,和之前的编辑页面添加跳转是类似的。

2. 添加映射关系显示

上面我们完成了删除的基本功能,但是在Djangoadmin中还额外的显示了表与表之间的关系,这里我们同样来实现这个功能。在实现是之前,我们需要先搞清楚一些关系。

在这里我将关联关系分为三大类:主动关联、被动关联与特殊关联。

  • 主动关联和被动关联都包含特殊关联。
  • 主动关联
    在当前表中有ForeignKey或者OneToOne关键字段,主动去关联其他表的方式为主动关联
  • 被动关联
    当前表中有ForeignKey或者OneToOne或者没有其中的任何一个,但是其他表通过ForeignKey或者OneToOne关联到该表的方式为被动关联。
  • 特殊关联
    当前表中有ManyToMany关联其他表格,或其他表中有 ManyToMany关联到该表,或有第三张额外的表中包括两个ForeignKey,将两个表关联起来的方式为特殊关联。

这里只是本人自己区分的一种方式!

这里的删除功能需要的是被动关联和特殊关联的关系显示。

2.1 shell中查询关系

这里以Customer表和UserProfile表为例:

 1 >>> python  manage.py  shell
 2
 3 >>> from  CRM import  models
 4 >>> a = models.Customer
 5 >>> a
 6 <class ‘CRM.models.Customer‘>
 7 >>> a._meta
 8 <Options for Customer>
 9 >>> a._meta.get_fields(include_hidden=True)
10 (<ManyToOneRel: CRM.customer_tags>, <ManyToOneRel: CRM.customerfollowup>, <ManyToOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>, <django.db.models.fields.AutoField: id>, <djan
11 go.db.models.fields.CharField: name>, <django.db.models.fields.CharField: qq>, <django.db.models.fields.CharField: qq_name>, <django.db.models.fields.CharField: phone>, <django.db.m
12 odels.fields.SmallIntegerField: source>, <django.db.models.fields.CharField: referral_from>, <django.db.models.fields.related.ForeignKey: consult_course>, <django.db.models.fields.T
13 extField: content>, <django.db.models.fields.SmallIntegerField: status>, <django.db.models.fields.related.ForeignKey: consultant>, <django.db.models.fields.TextField: memo>, <django
14 .db.models.fields.DateTimeField: date>, <django.db.models.fields.related.ManyToManyField: tags>)

上面我们能看到所有的字段信息,我们想看的信息如下:

 1 #被动关联
 2 <ManyToOneRel: CRM.customer_tags>
 3 <ManyToOneRel: CRM.customerfollowup>
 4 <ManyToOneRel: CRM.enrollment>
 5 <ManyToOneRel: CRM.payment>
 6 #主动关联
 7 <django.db.models.fields.related.ForeignKey: consult_course>
 8 <django.db.models.fields.related.ForeignKey: consultant>
 9 <django.db.models.fields.related.ManyToManyField: tags>
10 #特殊关联
11 <django.db.models.fields.related.ManyToManyField: tags>

我们需要找到的就是被动关联与特殊关联,其中特殊关联的另外一种形式,我们可以看看UserProfile表:

1 >>> c = models.UserProfile
2 >>> c._meta.get_fields(include_hidden=True)
3 (<ManyToOneRel: CRM.customer>, <ManyToOneRel: CRM.customerfollowup>, <ManyToOneRel: CRM.classlist_teachers>, <ManyToManyRel: CRM.classlist>, <ManyToOneRel: CRM.courserecord>, <ManyT
4 oOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>, <ManyToOneRel: CRM.userprofile_roles>, <django.db.models.fields.AutoField: id>, <django.db.models.fields.related.OneToOneField
5 : user>, <django.db.models.fields.CharField: name>, <django.db.models.fields.related.ManyToManyField: roles>)

提取需要的信息如下:

 1 #被动关联
 2 <ManyToOneRel: CRM.customer>
 3 <ManyToOneRel: CRM.customerfollowup>
 4 <ManyToOneRel: CRM.classlist_teachers>
 5 <ManyToManyRel: CRM.classlist>
 6 <ManyToOneRel: CRM.courserecord>
 7 <ManyToOneRel: CRM.enrollment>
 8 <ManyToOneRel: CRM.payment>
 9 <ManyToOneRel: CRM.userprofile_roles>
10 #主动关联
11 <django.db.models.fields.related.OneToOneField: user>
12 <django.db.models.fields.related.ManyToManyField: roles>
13 #特殊关联
14 <ManyToManyRel: CRM.classlist> 

上面两个表,为我们展示了几种关联的基本样式。接下来工作就是如何找到具体的关联样式。

下面演示的操作以Customer表和UserProfile表为例。

由于被动关系包括特殊关系,先来查询被动关系:

1.查询被动关系

1 Customer表
2
3 >>> models.Customer._meta.related_objects
4 (<ManyToOneRel: CRM.customerfollowup>, <ManyToOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>)
5 UserProfile表
6
7 >>> models.UserProfile._meta.related_objects
8 (<ManyToOneRel: CRM.customer>, <ManyToOneRel: CRM.customerfollowup>, <ManyToManyRel: CRM.classlist>, <ManyToOneRel: CRM.courserecord>, <ManyToOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>)

特殊关系是被动和主动关系都有的,这里所查询的应该是主动关系里面的特殊关系:

2. 查询特殊关系

 1 Customer表
 2
 3 >>> models.Customer._meta.many_to_many
 4 (<django.db.models.fields.related.ManyToManyField: tags>,)   #元组形式
 5 >>> models.Customer._meta.local_many_to_many
 6 [<django.db.models.fields.related.ManyToManyField: tags>]  #列表形式
 7 UserProfile表
 8
 9 >>> models.UserProfile._meta.local_many_to_many
10 [<django.db.models.fields.related.ManyToManyField: roles>]  #列表
11 >>> models.UserProfile._meta.many_to_many
12 (<django.db.models.fields.related.ManyToManyField: roles>,)  #元组
13 2.2 关联数据获取

2.2 关联数据获取

上面找到了具体的关联,该怎么获取到相关联的数据呢?
:请看下面。

通常情况下,我们跨表查询是使用关联的表名_set进行反向查询,跳转到关联表中,然后在获取数据。在这里也是同样的道理,演示还是在shell中操作。

Customer表为例:

1 >>> models.Customer._meta.related_objects
2 (<ManyToOneRel: CRM.customerfollowup>, <ManyToOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>)
3 >>> a= models.Customer._meta.related_objects
4 >>> for i in a:print(i,‘----‘,i.get_accessor_name())
5 ...
6 <ManyToOneRel: CRM.customerfollowup> ---- customerfollowup_set
7 <ManyToOneRel: CRM.enrollment> ---- enrollment_set
8 <ManyToOneRel: CRM.payment> ---- payment_set

这里的关联的表名_set就是我们所需要的。

由于在Customer表中没有被动关联中的特殊关联,所以我们以Tag表来反查到Customer表中数据:
你的数据库中一定要有数据

 1 >>> a = models.Tag.objects.filter(id=‘4‘)
 2 >>> a
 3 <QuerySet [<Tag: dsfgb>]>
 4
 5 #遍历出QuerySet集合里面的每个对象
 6 >>> for obj in a:
 7         #获取到每个对象对应的被动关联
 8 ...     for i in obj._meta.related_objects:
 9             # 通过反查方式获取到关联数据的对象集合
10 ...         b = getattr(obj,i.get_accessor_name()).select_related()
11             #遍历对象集合
12 ...         for data in b:
13 ...             print(data)
14 ...
15 4567467

好了,我们的目标实现了!下面的工作就交给神器:自定义标签。

2.3 创建标签函数

templatetags/tags.py下创建功能函数:

 1 ...
 2
 3 <-------------------获取删除映射关系--------------------------------
 4
 5 @register.simple_tag
 6 def display_object_related(object_list):
 7     return mark_safe(recursive_related_objs_lookup(object_list))
 8
 9
10 <-----------------递归获取映射关系--------------------------------
11
12 def recursive_related_objs_lookup(object_list):
13     #标签的拼接
14     #最外层ul
15     print(object_list)
16     ul_ele = "<ul style=‘color: pink‘>"
17     for obj in object_list:
18         print(obj._meta.verbose_name, obj.__str__().strip("<>"))
19         li_ele = ‘‘‘<li>{0}:{1}</li>‘‘‘.format(obj._meta.verbose_name, obj.__str__().strip("<>"))
20         ul_ele += li_ele
21
22         #映射关系处理
23         <---------------------------特殊关联处理-----------------------------------
24         #多对多关系
25         for m2m_field in obj._meta.local_many_to_many: #local_many_to_many返回列表,many_to_many返回元祖
26             sub_ul_ele = "<ul style=‘color: red‘>"
27             m2m_field_obj = getattr(obj, m2m_field.name)
28             for m2m_data in m2m_field_obj.select_related():
29                 sub_li_ele = ‘‘‘<li>{0}:{1}</li>‘‘‘.format(m2m_field.verbose_name, m2m_data.__str__().strip("<>"))
30                 sub_ul_ele += sub_li_ele
31
32             sub_ul_ele += ‘</ul>‘
33             #与外层拼接
34             ul_ele += sub_ul_ele
35
36         <---------------------------被动关联处理------------------------------------
37         #被动关联中的特殊关联处理
38         for related_obj in obj._meta.related_objects:
39             #判断是否存在特殊关联,特殊关联处理
40             if ‘ManyToManyRel‘ in related_obj.__repr__():
41                 #判断对象中是否包含反查属性
42                 if hasattr(obj, related_obj.get_accessor_name()):
43                     #获取反查对应的对象
44                     accessor_obj = getattr(obj, related_obj.get_accessor_name())
45                     #判断有没有获取数据的方法或属性
46                     if hasattr(accessor_obj, ‘select_related‘):
47                         target_object = accessor_obj.select_related()
48                         #标签拼接
49                         sub_ul_ele = ‘<ul style="color: green">‘
50                         for data in target_object:
51                             sub_li_ele = ‘‘‘<li>{0}:{1}</li>‘‘‘.format(data._meta.verbose_name,
52                                                                        data.__str__().strip("<>"))
53                             sub_ul_ele += sub_li_ele
54                         sub_ul_ele += ‘</ul>‘
55                         #与外层拼接
56                         ul_ele += sub_ul_ele
57             #被动关联处理
58             elif hasattr(obj, related_obj.get_accessor_name()):
59                 accessor_obj = getattr(obj, related_obj.get_accessor_name())
60                 if hasattr(accessor_obj, ‘select_related‘):
61                     target_object = accessor_obj.select_related()
62                     <---------------由于使用递归,下面的标签样会发生重复,就不需要使用了--------------------
63                     # sub_ul_ele = ‘<ul style="color: grey">‘
64                     # for data in target_data:
65                     #     sub_li_ele = ‘‘‘<li>{0}:{1}</li>‘‘‘.format(data._meta.verbose_name,
66                     #                                                data.__str__().strip("<>"))
67                     #     sub_ul_ele += sub_li_ele
68                     # sub_ul_ele += ‘</ul>‘
69                     # # 与外层拼接
70                     # ul_ele += sub_ul_ele
71                 else:
72                     print(‘One-To-One:‘,accessor_obj)
73                     target_object = accessor_obj
74                 #判断有无下级对象存在
75                 if len(target_object) > 0:
76                     node = recursive_related_objs_lookup(target_object)
77                     ul_ele += node
78
79     ul_ele += ‘</ul>‘
80     return ul_ele

2.4 模板调用标签

在编辑好的table_object_delete.html文件中添加:

 1 {% extends ‘king_admin/table_index.html‘ %}
 2 {% load tags %}
 3
 4 {% block body-content %}
 5
 6     {# 显示映射关系 #}
 7     {% display_object_related object_list %}
 8
 9     {# 表单提交  #}
10     <form method="post">
11         {% csrf_token %}
12         <input type="submit" class="btn btn-danger" value="Yes,I‘m sure">
13         <input type="hidden" value="yes" name="delete_confirm">
14         <a class="btn btn-info" href="{% url ‘king_admin:table_object_edit‘ app_name table_name object_id %}">No,Take me back</a>
15     </form>
16 {% endblock %}

删除效果如下:

其他的修饰内容,可自行添加,反正我是最后套模板。

时间: 2024-11-06 10:11:46

项目一:CRM(客户关系管理系统)--8的相关文章

Django项目:CRM(客户关系管理系统)--70--60PerfectCRM实现CRM学生上课记录

1 #urls.py 2 3 """PerfectCRM URL Configuration 4 5 The `urlpatterns` list routes URLs to views. For more information please see: 6 https://docs.djangoproject.com/en/2.0/topics/http/urls/ 7 Examples: 8 Function views 9 1. Add an import: from

Django项目:CRM(客户关系管理系统)--82--72PerfectCRM实现CRM动态菜单和角色

1 #models.py 2 3 # --------01PerfectCRM基本配置ADMIN-------- 4 5 from django.db import models 6 # Create your models here. 7 8 """ 9 #运行 Terminal 10 # 生成 数据表 11 # python manage.py makemigrations 12 # 数据表 迁移 13 # python manage.py migrate 14 &quo

Django项目:CRM(客户关系管理系统)--71--61PerfectCRM实现CRM学生上传作业

1 # student_urls.py 2 # --------60PerfectCRM实现CRM学生上课记录-------- 3 from django.conf.urls import url 4 from bpm.student import student_views 5 6 urlpatterns = [ 7 url(r'^student_course/$', student_views.student_course, name='student_course'), #学生报名的课程

Django项目:CRM(客户关系管理系统)--61--51PerfectCRM实现CRM客户报名流程学生合同上传照片

1 # sales_views.py 2 # --------47PerfectCRM实现CRM客户报名流程-------- 3 from django.db import IntegrityError #主动捕捉错误信息 4 from django.shortcuts import render #页面返回 5 from crm import models #数据库 6 from bpm.bpm_auxiliary import bpm_forms #自定制 forms 7 8 # -----

Django项目:CRM(客户关系管理系统)--67--57PerfectCRM实现CRM客户报名缴费链接

. 1 # kingadmin.py 2 # --------04PerfectCRM实现King_admin注册功能-------- 3 from crm import models 4 #print("kingadmin crm",models.Customer) 5 6 # --------05PerfectCRM实现King_admin注册功能获取内存-------- 7 # from king_admin.base_admin import register,BaseAdmi

Django项目:CRM(客户关系管理系统)--69--59PerfectCRM实现king_admin批量生成上课记录

1 # kingadmin.py 2 # --------04PerfectCRM实现King_admin注册功能-------- 3 from crm import models 4 #print("kingadmin crm",models.Customer) 5 6 # --------05PerfectCRM实现King_admin注册功能获取内存-------- 7 # from king_admin.base_admin import register,BaseAdmin

Django项目:CRM(客户关系管理系统)--66--56PerfectCRM实现CRM客户报名缴费链接

1 # kingadmin.py 2 # --------04PerfectCRM实现King_admin注册功能-------- 3 from crm import models 4 #print("kingadmin crm",models.Customer) 5 6 # --------05PerfectCRM实现King_admin注册功能获取内存-------- 7 # from king_admin.base_admin import register,BaseAdmin

Django项目:CRM(客户关系管理系统)--43--335PerfectCRM实现CRM重写Admin密码修改

1 # king_urls.py 2 # --------02PerfectCRM创建ADMIN页面-------- 3 from django.conf.urls import url 4 from king_admin import views 5 6 urlpatterns = [ 7 url(r'^$', views.app_index),#主页 8 9 # --------21PerfectCRM实现King_admin查看页面美化-------- 10 url(r'^(\w+)/$'

Django项目:CRM(客户关系管理系统)--40--32PerfectCRM实现King_admin添加不进行限制

1 # forms.py 2 # --------19PerfectCRM实现King_admin数据修改-------- 3 from django import forms 4 from crm import models 5 6 # class CustomerModelForm(forms.ModelForm): 7 # class Meta: #调用内置方法 8 # model = models.Customer #获取表名 9 # fields = "__all__" #字

Django项目:CRM(客户关系管理系统)--45--36PerfectCRM实现CRM用户登陆注销02

图片另存为  16*16  名字修改为      global_logo.jpg 1 /*! 2 3 *bootstrap.js 4 * 5 * Bootstrap v3.3.7 (http://getbootstrap.com) 6 * Copyright 2011-2016 Twitter, Inc. 7 * Licensed under the MIT license 8 */ 9 10 if (typeof jQuery === 'undefined') { 11 throw new E