1. 程式人生 > >項目一:CRM(客戶關系管理系統)--8

項目一:CRM(客戶關系管理系統)--8

保存 關聯 red 相關 ces xtend button enable method

添加、修改頁面都已經搞定,就差刪除功能啦!刪除這裏就比較麻煩了,麻煩在那些表之間的關系。

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 %}

刪除效果如下:

技術分享圖片

其他的修飾內容,可自行添加,反正我是最後套模板。

項目一:CRM(客戶關系管理系統)--8