CRM项目(八)
CRM项目开发(八)
|
文章目录 1. 添加删除功能 1.1 删除页面路由 1.2 添加删除页面模板 1.3 视图函数 1.4 为删除页面添加入口 2. 添加映射关系显示 2.1 shell中查询关系 2.2 关联数据获取 2.3 创建标签函数 2.4 模板调用标签 |
添加、修改页面都已经搞定,就差删除功能啦!删除这里就比较麻烦了,麻烦在那些表之间的关系。
1. 添加删除功能
创建页面就没有添加删除功能的必要,只需要在编辑页面即可。
1.1 删除页面路由
为用户的良好体验,我们新增加一个删除显示页面,路由:
urlpatterns = [
url(r'^$', views.index, name='table_index'),
url(r'^(\w+)/(\w+)/$', views.display_objects, name='display_objects'),
url(r'^(\w+)/(\w+)/(\d+)/edit/$', views.table_object_edit,name="table_object_edit"),
url(r'^(\w+)/(\w+)/add/$', views.table_object_add,name="table_object_add"),
url(r'^(\w+)/(\w+)/(\d+)/delete/$', views.table_object_delete,name="table_object_delete"),#删除路由
]
1.2 添加删除页面模板
在templates/king_admin目录下新建table_object_delete.html文件,内容如下:
{% extends 'king_admin/table_index.html' %}
{% block body-content %}
{# 表单提交 #}
<form method="post">
{% csrf_token %}
<input type="submit" class="btn btn-danger" value="Yes,I'm sure">
<input type="hidden" value="yes" name="delete_confirm">
<a class="btn btn-info" href="{% url 'king_admin:table_object_edit' app_name table_name object_id %}">No,Take me back</a>
</form>
{% endblock %}
1.3 视图函数
def table_object_delete(request, app_name, table_name, object_id):
admin_class = site.enabled_admins[app_name][table_name]
object_list = admin_class.model.objects.filter(id=object_id)
if request.method == 'POST':
if request.POST.get('delete_confirm') == 'yes':
object_list.delete()
return redirect('/king_admin/{app_name}/{table_name}'.format(app_name=app_name, table_name=table_name))
return render(request, 'king_admin/table_object_delete.html', {'app_name': app_name,
'table_name': table_name,
'object_id': object_id,
'object_list': object_list})
1.4 为删除页面添加入口
在table_object_edit.html文件中,只需要添加一个按钮,但是这个按钮很是关键 ,要经过一些特别的处理,避免一些不必要的问题发生。
...
{% endfor %}
{# 添加保存按钮 #}
<div class="form-group">
{# 添加删除功能,并独立出来,以免影响其他功能 #}
{% block obj_delete %}
<div class="col-sm-2">
<a class="btn btn-danger" href="{% url 'king_admin:table_object_delete' app_name table_name object_id %}">删除</a>
</div>
{% endblock %}
<div class="col-sm-10 ">
<button type="submit" class="btn btn-success pull-right">保存</button>
</div>
</div>
</form>
...
还记得,我们的添加功能是继承自编辑页面吧,那里同样也要加上继承标签,以免二者出现一些关联错误。
在table_object_add.html页面添加一个块标签即可,且不加任何内容:
...
{% block obj_delete %}
{% endblock %}
渲染后的效果:

删除后跳转到显示页面的功能在视图函数中已经写好,不在赘述,和之前的编辑页面添加跳转是类似的。
2. 添加映射关系显示
上面我们完成了删除的基本功能,但是在Django的admin中还额外的显示了表与表之间的关系,这里我们同样来实现这个功能。在实现是之前,我们需要先搞清楚一些关系。
在这里我将关联关系分为三大类:主动关联、被动关联与特殊关联。
-
主动关联和被动关联都包含特殊关联。
-
主动关联
在当前表中有ForeignKey或者OneToOne关键字段,主动去关联其他表的方式为主动关联 -
被动关联
当前表中有ForeignKey或者OneToOne或者没有其中的任何一个,但是其他表通过ForeignKey或者OneToOne关联到该表的方式为被动关联。 -
特殊关联
当前表中有ManyToMany关联其他表格,或其他表中有ManyToMany关联到该表,或有第三张额外的表中包括两个ForeignKey,将两个表关联起来的方式为特殊关联。
这里只是本人自己区分的一种方式!
这里的删除功能需要的是被动关联和特殊关联的关系显示。
2.1 shell中查询关系
这里以Customer表和UserProfile表为例:
>>> python manage.py shell >>> from CRM import models >>> a = models.Customer >>> a <class 'CRM.models.Customer'> >>> a._meta <Options for Customer> >>> a._meta.get_fields(include_hidden=True) (<ManyToOneRel: CRM.customer_tags>, <ManyToOneRel: CRM.customerfollowup>, <ManyToOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>, <django.db.models.fields.AutoField: id>, <djan 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 odels.fields.SmallIntegerField: source>, <django.db.models.fields.CharField: referral_from>, <django.db.models.fields.related.ForeignKey: consult_course>, <django.db.models.fields.T extField: content>, <django.db.models.fields.SmallIntegerField: status>, <django.db.models.fields.related.ForeignKey: consultant>, <django.db.models.fields.TextField: memo>, <django .db.models.fields.DateTimeField: date>, <django.db.models.fields.related.ManyToManyField: tags>)
上面我们能看到所有的字段信息,我们想看的信息如下:
#被动关联 <ManyToOneRel: CRM.customer_tags> <ManyToOneRel: CRM.customerfollowup> <ManyToOneRel: CRM.enrollment> <ManyToOneRel: CRM.payment> #主动关联 <django.db.models.fields.related.ForeignKey: consult_course> <django.db.models.fields.related.ForeignKey: consultant> <django.db.models.fields.related.ManyToManyField: tags> #特殊关联 <django.db.models.fields.related.ManyToManyField: tags>
我们需要找到的就是被动关联与特殊关联,其中特殊关联的另外一种形式,我们可以看看UserProfile表:
>>> c = models.UserProfile >>> c._meta.get_fields(include_hidden=True) (<ManyToOneRel: CRM.customer>, <ManyToOneRel: CRM.customerfollowup>, <ManyToOneRel: CRM.classlist_teachers>, <ManyToManyRel: CRM.classlist>, <ManyToOneRel: CRM.courserecord>, <ManyT oOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>, <ManyToOneRel: CRM.userprofile_roles>, <django.db.models.fields.AutoField: id>, <django.db.models.fields.related.OneToOneField : user>, <django.db.models.fields.CharField: name>, <django.db.models.fields.related.ManyToManyField: roles>)
提取需要的信息如下:
#被动关联 <ManyToOneRel: CRM.customer> <ManyToOneRel: CRM.customerfollowup> <ManyToOneRel: CRM.classlist_teachers> <ManyToManyRel: CRM.classlist> <ManyToOneRel: CRM.courserecord> <ManyToOneRel: CRM.enrollment> <ManyToOneRel: CRM.payment> <ManyToOneRel: CRM.userprofile_roles> #主动关联 <django.db.models.fields.related.OneToOneField: user> <django.db.models.fields.related.ManyToManyField: roles> #特殊关联 <ManyToManyRel: CRM.classlist>
上面两个表,为我们展示了几种关联的基本样式。接下来工作就是如何找到具体的关联样式。
下面演示的操作以Customer表和UserProfile表为例。
由于被动关系包括特殊关系,先来查询被动关系:
- 查询被动关系
Customer表 >>> models.Customer._meta.related_objects (<ManyToOneRel: CRM.customerfollowup>, <ManyToOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>) UserProfile表 >>> models.UserProfile._meta.related_objects (<ManyToOneRel: CRM.customer>, <ManyToOneRel: CRM.customerfollowup>, <ManyToManyRel: CRM.classlist>, <ManyToOneRel: CRM.courserecord>, <ManyToOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>)
特殊关系是被动和主动关系都有的,这里所查询的应该是主动关系里面的特殊关系:
- 查询特殊关系
Customer表 >>> models.Customer._meta.many_to_many (<django.db.models.fields.related.ManyToManyField: tags>,) #元组形式 >>> models.Customer._meta.local_many_to_many [<django.db.models.fields.related.ManyToManyField: tags>] #列表形式 UserProfile表 >>> models.UserProfile._meta.local_many_to_many [<django.db.models.fields.related.ManyToManyField: roles>] #列表 >>> models.UserProfile._meta.many_to_many (<django.db.models.fields.related.ManyToManyField: roles>,) #元组
2.2 关联数据获取
上面找到了具体的关联,该怎么获取到相关联的数据呢?
答:请看下面。
通常情况下,我们跨表查询是使用关联的表名_set进行反向查询,跳转到关联表中,然后在获取数据。在这里也是同样的道理,演示还是在shell中操作。
以Customer表为例:
>>> models.Customer._meta.related_objects (<ManyToOneRel: CRM.customerfollowup>, <ManyToOneRel: CRM.enrollment>, <ManyToOneRel: CRM.payment>) >>> a= models.Customer._meta.related_objects >>> for i in a:print(i,'----',i.get_accessor_name()) ... <ManyToOneRel: CRM.customerfollowup> ---- customerfollowup_set <ManyToOneRel: CRM.enrollment> ---- enrollment_set <ManyToOneRel: CRM.payment> ---- payment_set
这里的关联的表名_set就是我们所需要的。
由于在Customer表中没有被动关联中的特殊关联,所以我们以Tag表来反查到Customer表中数据:
(你的数据库中一定要有数据)
>>> a = models.Tag.objects.filter(id='4')
>>> a
<QuerySet [<Tag: dsfgb>]>
#遍历出QuerySet集合里面的每个对象
>>> for obj in a:
#获取到每个对象对应的被动关联
... for i in obj._meta.related_objects:
# 通过反查方式获取到关联数据的对象集合
... b = getattr(obj,i.get_accessor_name()).select_related()
#遍历对象集合
... for data in b:
... print(data)
...
4567467
好了,我们的目标实现了!下面的工作就交给神器:自定义标签。
2.3 创建标签函数
在templatetags/tags.py下创建功能函数:
... <-------------------获取删除映射关系-------------------------------- @register.simple_tag def display_object_related(object_list): return mark_safe(recursive_related_objs_lookup(object_list)) <-----------------递归获取映射关系-------------------------------- def recursive_related_objs_lookup(object_list): #标签的拼接 #最外层ul print(object_list) ul_ele = "<ul style='color: pink'>" for obj in object_list: print(obj._meta.verbose_name, obj.__str__().strip("<>")) li_ele = '''<li>{0}:{1}</li>'''.format(obj._meta.verbose_name, obj.__str__().strip("<>")) ul_ele += li_ele #映射关系处理 <---------------------------特殊关联处理----------------------------------- #多对多关系 for m2m_field in obj._meta.local_many_to_many: #local_many_to_many返回列表,many_to_many返回元祖 sub_ul_ele = "<ul style='color: red'>" m2m_field_obj = getattr(obj, m2m_field.name) for m2m_data in m2m_field_obj.select_related(): sub_li_ele = '''<li>{0}:{1}</li>'''.format(m2m_field.verbose_name, m2m_data.__str__().strip("<>")) sub_ul_ele += sub_li_ele sub_ul_ele += '</ul>' #与外层拼接 ul_ele += sub_ul_ele <---------------------------被动关联处理------------------------------------ #被动关联中的特殊关联处理 for related_obj in obj._meta.related_objects: #判断是否存在特殊关联,特殊关联处理 if 'ManyToManyRel' in related_obj.__repr__(): #判断对象中是否包含反查属性 if hasattr(obj, related_obj.get_accessor_name()): #获取反查对应的对象 accessor_obj = getattr(obj, related_obj.get_accessor_name()) #判断有没有获取数据的方法或属性 if hasattr(accessor_obj, 'select_related'): target_object = accessor_obj.select_related() #标签拼接 sub_ul_ele = '<ul style="color: green">' for data in target_object: sub_li_ele = '''<li>{0}:{1}</li>'''.format(data._meta.verbose_name, data.__str__().strip("<>")) sub_ul_ele += sub_li_ele sub_ul_ele += '</ul>' #与外层拼接 ul_ele += sub_ul_ele #被动关联处理 elif hasattr(obj, related_obj.get_accessor_name()): accessor_obj = getattr(obj, related_obj.get_accessor_name()) if hasattr(accessor_obj, 'select_related'): target_object = accessor_obj.select_related() <---------------由于使用递归,下面的标签样会发生重复,就不需要使用了-------------------- # sub_ul_ele = '<ul style="color: grey">' # for data in target_data: # sub_li_ele = '''<li>{0}:{1}</li>'''.format(data._meta.verbose_name, # data.__str__().strip("<>")) # sub_ul_ele += sub_li_ele # sub_ul_ele += '</ul>' # # 与外层拼接 # ul_ele += sub_ul_ele else: print('One-To-One:',accessor_obj) target_object = accessor_obj #判断有无下级对象存在 if len(target_object) > 0: node = recursive_related_objs_lookup(target_object) ul_ele += node ul_ele += '</ul>' return ul_ele
2.4 模板调用标签
在编辑好的table_object_delete.html文件中添加:
{% extends 'king_admin/table_index.html' %}
{% load tags %}
{% block body-content %}
{# 显示映射关系 #}
{% display_object_related object_list %}
{# 表单提交 #}
<form method="post">
{% csrf_token %}
<input type="submit" class="btn btn-danger" value="Yes,I'm sure">
<input type="hidden" value="yes" name="delete_confirm">
<a class="btn btn-info" href="{% url 'king_admin:table_object_edit' app_name table_name object_id %}">No,Take me back</a>
</form>
{% endblock %}
删除效果如下:

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

浙公网安备 33010602011771号