Python CRM项目二

一.准备工作

如果没有配置基本的项目,请参考 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视图
View Code

配置每个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 ]
View Code

2.crm

1 urlpatterns = [
2     url(r'^$',views.index,name='sales_index'),#销售首页
3     url(r'customers/',views.customer_list,name='customer_list'),#客户库
4 ]
View Code

3.student

1 urlpatterns = [
2     #学生首页   
3     url(r'^$',views.index,name='stu_index'),
4 ]
View Code

4.king_admin

1 urlpatterns = [
2     #表首页
3     url(r'^$',views.index,name='table_index'),
4 ]
View Code

配置每个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')
View Code

2.student

1 def index(request):
2     #返回学生首页
3     return render(request,'student/index.html')
View Code

3.king_admin

1 def index(request):
2     #返回表格管理页面
3     return render(request, 'king_admin/table_index.html',{'table_list':king_admin.enabled_admins})
View Code

配置前端页面

模板使用: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>
View Code

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

然后在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 = '角色'
View Code

同步数据库,启动项目,进入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 ('转行');
View Code

菜单表

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');
View Code

角色表

1 INSERT INTO prefect_crm.crm_role (name) VALUES ('学生');
2 INSERT INTO prefect_crm.crm_role (name) VALUES ('销售');
View Code

角色和菜单的关联表

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);
View Code

用户表

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);
View Code

用户角色关联表

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);
View Code

课程表

1 INSERT INTO prefect_crm.crm_course (name, price, period, outline) VALUES ('Python', 18900, 5, '1.python语法
2 2.python基础
3 3.前端
4 4.项目');
View Code

客户表

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);
View Code

客户和标签的关系表

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);
View Code

在此列出这些数据表,但是我们在Django admin自带的后台管理中,不需要插入中间表,系统会自动在中间表中关联,此处只是说明表关系

二.动态菜单的展示

在配置完数据之后,首先在页面的右上角展示登录的用户名,在左侧菜单根据不同的用户展示不同的明细

因为userprofile中关联了Django自带的User,所以展示用户名只需要一行代码

在index.html中找到相应的行,替换即可

1 <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{ request.user }}</a>
View Code

因为在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 %}
View Code

这样动态菜单就设置完成

三.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
View Code

核心代码:

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
View Code

总体代码:

 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)
View Code

 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})
View Code

页面

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

以上步骤的展示效果

原文地址:https://www.cnblogs.com/luhuajun/p/7778633.html