一.准備工作
如果沒有配置基本的項目,請參考 http://www.cnblogs.com/luhuajun/p/7771196.html
當我們配置完成后首先准備我們的app
創建2個app分別對應學生,重寫的Admin模板
1 python manager.py startapp student #學生視圖 2 python manager.py startapp king_admin #king_admin視圖
配置每個app的url映射
1.主app
1 #將每個模塊的urls.py引入 2 urlpatterns = [ 3 url(r'^admin/', admin.site.urls), 4 url(r'^crm/',include('crm.urls')), 5 url(r'^student/',include('student.urls')), 6 url(r'^king_admin/',include('king_admin.urls')), 7 ]
2.crm
1 urlpatterns = [ 2 url(r'^$',views.index,name='sales_index'),#銷售首頁 3 url(r'customers/',views.customer_list,name='customer_list'),#客戶庫 4 ]
3.student
1 urlpatterns = [ 2 #學生首頁 3 url(r'^$',views.index,name='stu_index'), 4 ]
4.king_admin
1 urlpatterns = [ 2 #表首頁 3 url(r'^$',views.index,name='table_index'), 4 ]
配置每個url的視圖
1.crm
1 def index(request): 2 #返回銷售首頁 3 return render(request,'index.html',name='sales_index') 4 5 6 def customer_list(request): 7 #返回客戶庫首頁 8 return render(request,'sales/customers.html')
2.student
1 def index(request): 2 #返回學生首頁 3 return render(request,'student/index.html')
3.king_admin
1 def index(request): 2 #返回表格管理頁面 3 return render(request, 'king_admin/table_index.html',{'table_list':king_admin.enabled_admins})
配置前端頁面
模板使用:http://v3.bootcss.com/examples/dashboard/
將上面的模板下載,將css,js,文件按一下的層級結構歸類

下載的html文件進行分解,分解為base.html和index.html
base.html存放css文件和js文件
index.html繼承base.html然后在此基礎上進行定制
base.html
1 <!DOCTYPE html> 2 <html lang="zh-CN"> 3 <head> 4 <meta charset="utf-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <!-- 上述3個meta標簽*必須*放在最前面,任何其他內容都*必須*跟隨其后! --> 8 <meta name="description" content=""> 9 <meta name="author" content=""> 10 11 12 <title>oldboy CRM</title> 13 14 <!-- Bootstrap core CSS --> 15 <link href="/static/css/bootstrap.min.css" rel="stylesheet"> 16 17 <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> 18 <link href="/static/css/dashboard.css" rel="stylesheet"> 19 20 <!-- Custom styles for this template --> 21 <link href="/static/css/ie10-viewport-bug-workaround.css" rel="stylesheet"> 22 <link href="/static/plugins/dropzone/dropzone.css" rel="stylesheet"> 23 24 {% block css %}{% endblock %} 25 26 27 </head> 28 29 {% block body %}{% endblock %} 30 31 32 <script src="/static/js/jquery.min.js"></script> 33 <script src="/static/js/bootstrap.min.js"></script> 34 <script src="/static/js/holder.min.js"></script> 35 <script src="/static/js/ie10-viewport-bug-workaround.js"></script> 36 <script src="/static/plugins/dropzone/dropzone.js"></script> 37 {% block bottom-js %}{% endblock %} 38 </html>
index.html
1 {% extends 'base.html' %} 2 {% block body %} 3 <body> 4 <nav class="navbar navbar-inverse navbar-fixed-top"> 5 <div class="container-fluid"> 6 <div class="navbar-header"> 7 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> 8 <span class="sr-only">Toggle navigation</span> 9 <span class="icon-bar"></span> 10 <span class="icon-bar"></span> 11 <span class="icon-bar"></span> 12 </button> 13 <a class="navbar-brand" href="#">My CRM</a> 14 </div> 15 <div id="navbar" class="navbar-collapse collapse"> 16 <ul class="nav navbar-nav navbar-right"> 17 18 19 <li class="dropdown"> 20 <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{ request.user }}</a> 21 <ul class="dropdown-menu" role="menu"> 22 {# <li><a href="{% url 'acc_logout' %}">注銷</a></li>#} 23 </ul> 24 </li> 25 </ul> 26 27 </div> 28 </div> 29 </nav> 30 31 <div class="container-fluid"> 32 <div class="row"> 33 <div class="col-sm-3 col-md-2 sidebar"> 34 <ul class="nav nav-sidebar"> 35 {# {% for role in request.user.roles.all %}#} 36 {# {% for menu in role.menus.all %}#} 37 {# <li><a href="{% if menu.url_type == 0 %}{% url menu.url_name %}{% else %}{{ menu.url_name }}{% endif %}">{{ menu.name }}</a></li>#} 38 {# {% endfor %}#} 39 {# {% endfor %}#} 40 {% for role in request.user.userprofile.roles.all %} 41 {% for menu in role.menus.all %} 42 <li><a href="{% url menu.url_name %}">{{ menu.name }}</a></li> 43 {% endfor %} 44 {% endfor %} 45 </ul> 46 47 </div> 48 <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> 49 {% block page-content %} 50 <h1 class="page-header">Dashboard</h1> 51 <div class="row placeholders"> 52 <div class="col-xs-6 col-sm-3 placeholder"> 53 <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail"> 54 <h4>Label</h4> 55 <span class="text-muted">Something else</span> 56 </div> 57 <div class="col-xs-6 col-sm-3 placeholder"> 58 <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail"> 59 <h4>Label</h4> 60 <span class="text-muted">Something else</span> 61 </div> 62 <div class="col-xs-6 col-sm-3 placeholder"> 63 <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail"> 64 <h4>Label</h4> 65 <span class="text-muted">Something else</span> 66 </div> 67 <div class="col-xs-6 col-sm-3 placeholder"> 68 <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail"> 69 <h4>Label</h4> 70 <span class="text-muted">Something else</span> 71 </div> 72 </div> 73 74 75 <h2 class="sub-header">Section title</h2> 76 {% endblock %} 77 </div> 78 </div> 79 80 </div> 81 </body> 82 {% endblock %}
然后在template下創個各個app名稱的文件夾來存放不同app的頁面,目錄結構如下

然后啟動項目,看看每個url是否可以正常訪問
准備數據
在插入數據之前,由於本項目要是用動態菜單,所以還要創建一張菜單表和角色表進行關聯
1 class Menu(models.Model): 2 '''菜單表''' 3 name = models.CharField(max_length=32) 4 url_name = models.CharField(max_length=64,unique=True) 5 6 def __str__(self): 7 return self.name 8 class Meta: 9 verbose_name_plural = '菜單' 10 11 12 class Role(models.Model): 13 '''角色表''' 14 name = models.CharField(max_length=64,unique=True) 15 #新增菜單信息 16 menus = models.ManyToManyField('Menu',blank=True) 17 def __str__(self): 18 return self.name 19 20 class Meta: 21 verbose_name_plural = '角色'
同步數據庫,啟動項目,進入admin后台管理
在一些表中插入數據
首先插入tag表
1 INSERT INTO prefect_crm.crm_tag (name) VALUES ('土豪'); 2 INSERT INTO prefect_crm.crm_tag (name) VALUES ('屌絲'); 3 INSERT INTO prefect_crm.crm_tag (name) VALUES ('無基礎'); 4 INSERT INTO prefect_crm.crm_tag (name) VALUES ('有基礎'); 5 INSERT INTO prefect_crm.crm_tag (name) VALUES ('有工作經驗'); 6 INSERT INTO prefect_crm.crm_tag (name) VALUES ('沒文化'); 7 INSERT INTO prefect_crm.crm_tag (name) VALUES ('沒有工作經驗'); 8 INSERT INTO prefect_crm.crm_tag (name) VALUES ('轉行');
菜單表
1 INSERT INTO prefect_crm.crm_menu (name, url_name) VALUES ('銷售首頁', 'sales_index'); 2 INSERT INTO prefect_crm.crm_menu (name, url_name) VALUES ('學生首頁', 'stu_index'); 3 INSERT INTO prefect_crm.crm_menu (name, url_name) VALUES ('客戶庫', 'customer_list');
角色表
1 INSERT INTO prefect_crm.crm_role (name) VALUES ('學生'); 2 INSERT INTO prefect_crm.crm_role (name) VALUES ('銷售');
角色和菜單的關聯表
1 INSERT INTO prefect_crm.crm_role_menus (role_id, menu_id) VALUES (1, 1); 2 INSERT INTO prefect_crm.crm_role_menus (role_id, menu_id) VALUES (1, 3); 3 INSERT INTO prefect_crm.crm_role_menus (role_id, menu_id) VALUES (2, 2);
用戶表
1 INSERT INTO prefect_crm.crm_userprofile (name, user_id) VALUES ('Alex Li', 1); 2 INSERT INTO prefect_crm.crm_userprofile (name, user_id) VALUES ('Jack', 2);
用戶角色關聯表
1 INSERT INTO prefect_crm.crm_userprofile_roles (userprofile_id, role_id) VALUES (1, 1); 2 INSERT INTO prefect_crm.crm_userprofile_roles (userprofile_id, role_id) VALUES (2, 2);
課程表
1 INSERT INTO prefect_crm.crm_course (name, price, period, outline) VALUES ('Python', 18900, 5, '1.python語法 2 2.python基礎 3 3.前端 4 4.項目');
客戶表
1 INSERT INTO prefect_crm.crm_customer (name, qq, qq_name, phone, source, referral_from, content, memo, status, date, consult_course_id, consultant_id) VALUES ('大錘', '1234567890', '大錘', '1234567890', 1, '', '上課時間 2 上課地點 3 價格', '沒有報名', 'unregistered', '2017-10-17 01:48:53', 1, 1); 4 INSERT INTO prefect_crm.crm_customer (name, qq, qq_name, phone, source, referral_from, content, memo, status, date, consult_course_id, consultant_id) VALUES ('小錘', '1234567891', '小錘', '1234567891', 2, '', '價格 5 地點 6 學習周期', '有點低能', 'unregistered', '2017-10-17 01:49:49', 1, 1); 7 INSERT INTO prefect_crm.crm_customer (name, qq, qq_name, phone, source, referral_from, content, memo, status, date, consult_course_id, consultant_id) VALUES ('小悅悅', '1234567892', '小悅悅', '1234567892', 4, '', '價格 8 授課方式 9 是否有美女', '有強烈的學習意向', 'signed', '2017-10-17 01:52:12', 1, 2);
客戶和標簽的關系表
1 INSERT INTO prefect_crm.crm_customer_tags (customer_id, tag_id) VALUES (1, 4); 2 INSERT INTO prefect_crm.crm_customer_tags (customer_id, tag_id) VALUES (1, 7); 3 INSERT INTO prefect_crm.crm_customer_tags (customer_id, tag_id) VALUES (2, 2); 4 INSERT INTO prefect_crm.crm_customer_tags (customer_id, tag_id) VALUES (2, 5); 5 INSERT INTO prefect_crm.crm_customer_tags (customer_id, tag_id) VALUES (3, 2); 6 INSERT INTO prefect_crm.crm_customer_tags (customer_id, tag_id) VALUES (3, 8);
在此列出這些數據表,但是我們在Django admin自帶的后台管理中,不需要插入中間表,系統會自動在中間表中關聯,此處只是說明表關系
二.動態菜單的展示
在配置完數據之后,首先在頁面的右上角展示登錄的用戶名,在左側菜單根據不同的用戶展示不同的明細

因為userprofile中關聯了Django自帶的User,所以展示用戶名只需要一行代碼
在index.html中找到相應的行,替換即可
1 <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{ request.user }}</a>
因為在userprofile中已經關聯了role,而role關聯了菜單所以在前端可以直接循環userprofile來獲取菜單
在index.html中找到相應的行,替換即可
1 {% for role in request.user.userprofile.roles.all %} 2 {% for menu in role.menus.all %} 3 <li><a href="{% url menu.url_name %}">{{ menu.name }}</a></li> 4 {% endfor %} 5 {% endfor %}
這樣動態菜單就設置完成
三.king_admin動態綁定models
因為我們要重寫Django Admin的功能,所以首先分析Admin展示的數據結構
第一級是App
第二級是models
第三級是字段

所以數據結構是
{app_name:{model_name:model_object,model_name1:model_object1,model_name2:model_object2....},}
這樣的分層結構來封裝數據,並返回給前端展示
根據類自動獲取關聯的表名和app名稱
過程
1 #1.進入python交互環境 2 python manage.py shell 3 4 #2.找到app名稱 5 from crm import models 6 models.UserProfile._meta.app_config 7 8 #3.找到表名 9 models.UserProfile._meta.app_label
核心代碼:
1 def register(model_class,admin_class=None): 2 #如果不存再app,就新建一個字典,並且綁定admin_class和mode_class 3 if model_class._meta.app_label not in enabled_admins: 4 enabled_admins[model_class._meta.app_label] = {} 5 #綁定model對象和admin類,類似於admin的register方法 6 admin_class.model = model_class 7 #將字典的格式寫成{app:{'model_name':model_obj}}這種格式 8 enabled_admins[model_class._meta.app_label][model_class._meta.model_name] = admin_class
總體代碼:
1 from crm import models 2 enabled_admins = {} #全局字典 3 4 class BaseAdmin(object): 5 #基類 6 list_display = [] 7 list_filter = [] 8 9 #定制類 10 class CustomerFollowUpAdmin(BaseAdmin): 11 list_display = ['customer', 'consultant','date'] 12 13 class CustomerAdmin(BaseAdmin): 14 list_display = ['qq','name'] 15 #model = model.Customer 16 17 #綁定model和定制類的方法 18 def register(model_class,admin_class=None): 19 if model_class._meta.app_label not in enabled_admins: 20 enabled_admins[model_class._meta.app_label] = {} 21 admin_class.model = model_class#綁定model對象和admin類 22 enabled_admins[model_class._meta.app_label][model_class._meta.model_name] = admin_class 23 24 #注冊 25 register(models.Customer,CustomerAdmin)
1 from crm import models 2 enabled_admins = {} #全局字典 3 4 class BaseAdmin(object): 5 #基類定義一些展示方法 6 list_display = [] 7 list_filter = [] 8 9 class CustomerFollowUpAdmin(BaseAdmin): 10 #自定義展示 11 list_display = ['customer', 'consultant','date'] 12 13 class CustomerAdmin(BaseAdmin): 14 list_display = ['qq','name'] 15 #model = model.Customer 16 17 18 def register(model_class,admin_class=None): 19 if model_class._meta.app_label not in enabled_admins: 20 enabled_admins[model_class._meta.app_label] = {} 21 #綁定model對象和admin類 22 admin_class.model = model_class 23 enabled_admins[model_class._meta.app_label][model_class._meta.model_name] = admin_class 24 25 #注冊 26 register(models.Customer,CustomerAdmin) 27 register(models.CustomerFollowUp,CustomerFollowUp
視圖映射
1 from django.shortcuts import render 2 from king_admin import king_admin 3 # Create your views here. 4 def index(request): 5 6 return render(request, 'king_admin/table_index.html',{'table_list':king_admin.enabled_admins})
頁面
1 {% extends 'base.html' %} 2 {% block body %} 3 <body> 4 <nav class="navbar navbar-inverse navbar-fixed-top"> 5 <div class="container-fluid"> 6 <div class="navbar-header"> 7 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> 8 <span class="sr-only">Toggle navigation</span> 9 <span class="icon-bar"></span> 10 <span class="icon-bar"></span> 11 <span class="icon-bar"></span> 12 </button> 13 <a class="navbar-brand" href="#">My CRM</a> 14 </div> 15 <div id="navbar" class="navbar-collapse collapse"> 16 <ul class="nav navbar-nav navbar-right"> 17 18 19 <li class="dropdown"> 20 <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{ request.user }}</a> 21 <ul class="dropdown-menu" role="menu"> 22 {# <li><a href="{% url 'acc_logout' %}">注銷</a></li>#} 23 </ul> 24 </li> 25 </ul> 26 27 </div> 28 </div> 29 </nav> 30 31 <div class="container" style="margin-top:50px;"> 32 <div class="row"> 33 <div class="panel panel-info"> 34 <div class="panel-heading"> 35 <h3 class="panel-title">Panel title</h3> 36 </div> 37 <div class="panel-body"> 38 {% for app_name,app_tables in table_list.items %} 39 <table class="table table-hover"> 40 <thead> 41 <tr> 42 <th>{{ app_name }}</th> 43 </tr> 44 </thead> 45 46 <tbody> 47 {% for table_name,admin in app_tables.items %} 48 <tr> 49 <td>{{ table_name }}</td> 50 <td>add</td> 51 <td>change</td> 52 </tr> 53 {% endfor %} 54 </tbody> 55 56 </table> 57 {% endfor %} 58 </div> 59 </div> 60 </div> 61 </div> 62 63 64 </body> 65 {% endblock %}
以上步驟的展示效果

