• 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

    以上步骤的展示效果

  • 相关阅读:
    查询类里面对象个数
    动手动脑2
    关于随机数的产生-动手动脑1
    单词频率代码测试
    反码补码报告
    动手动脑课上总结
    java开学第一周测试代码
    【P1825】表达式整除
    工程代码の初體驗
    差分:IncDec Sequence 差分数组
  • 原文地址:https://www.cnblogs.com/luhuajun/p/7778633.html
Copyright © 2020-2023  润新知