Django:CRM - 相关功能分解(1)

客户列表的展示(公和私)

本项目中的后台页面是基于后台模板的,因此,需要就是 母版

上面和侧边栏基于母版样式,其中内容区域 和  js 部分添加了 block盒子

<!DOCTYPE html>
<!--
This is a starter template page. Use this page to start your new project from
scratch. This page gets rid of all links and provides the needed markup only.
-->
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>CRM</title>
  <!-- Tell the browser to be responsive to screen width -->
  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
  <!-- Bootstrap 3.3.6 -->
  <link rel="stylesheet" href="/static/AdminLTE-2.3.3/bootstrap/css/bootstrap.min.css">
  <!-- Font Awesome -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
  <!-- Ionicons -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css">
  <!-- Theme style -->
  <link rel="stylesheet" href="/static/AdminLTE-2.3.3/dist/css/AdminLTE.min.css">
  <!-- AdminLTE Skins. We have chosen the skin-blue for this starter
        page. However, you can choose any other skin. Make sure you
        apply the skin class to the body tag so the changes take effect.
  -->
  <link rel="stylesheet" href="/static/AdminLTE-2.3.3/dist/css/skins/skin-blue.min.css">
    <link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.css">

  <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
  <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
  <!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  <![endif]-->
</head>
<!--
BODY TAG OPTIONS:
=================
Apply one or more of the following classes to get the
desired effect
|---------------------------------------------------------|
| SKINS         | skin-blue                               |
|               | skin-black                              |
|               | skin-purple                             |
|               | skin-yellow                             |
|               | skin-red                                |
|               | skin-green                              |
|---------------------------------------------------------|
|LAYOUT OPTIONS | fixed                                   |
|               | layout-boxed                            |
|               | layout-top-nav                          |
|               | sidebar-collapse                        |
|               | sidebar-mini                            |
|---------------------------------------------------------|
-->
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">

  <!-- Main Header -->
  <header class="main-header">

    <!-- Logo -->
    <a href="/static/AdminLTE-2.3.3/index2.html" class="logo">

      <!-- logo for regular state and mobile devices -->
      <span class="logo-lg"><b>CRM</b></span>
    </a>

    <!-- Header Navbar -->
    <nav class="navbar navbar-static-top" role="navigation">
      <!-- Sidebar toggle button-->
      <a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
        <span class="sr-only">Toggle navigation</span>
      </a>
      <!-- Navbar Right Menu -->
      <div class="navbar-custom-menu">
        <ul class="nav navbar-nav">
          <!-- Messages: style can be found in dropdown.less-->
          <li class="dropdown messages-menu">
            <!-- Menu toggle button -->
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
              <i class="fa fa-envelope-o"></i>
              <span class="label label-success">4</span>
            </a>
            <ul class="dropdown-menu">
              <li class="header">You have 4 messages</li>
              <li>
                <!-- inner menu: contains the messages -->
                <ul class="menu">
                  <li><!-- start message -->
                    <a href="#">
                      <div class="pull-left">
                        <!-- User Image -->
                        <img src="/static/AdminLTE-2.3.3/dist/img/user2-160x160.jpg" class="img-circle" alt="User Image">
                      </div>
                      <!-- Message title and timestamp -->
                      <h4>
                        Support Team
                        <small><i class="fa fa-clock-o"></i> 5 mins</small>
                      </h4>
                      <!-- The message -->
                      <p>Why not buy a new awesome theme?</p>
                    </a>
                  </li>
                  <!-- end message -->
                </ul>
                <!-- /.menu -->
              </li>
              <li class="footer"><a href="#">See All Messages</a></li>
            </ul>
          </li>
          <!-- /.messages-menu -->

          <!-- Notifications Menu -->
          <li class="dropdown notifications-menu">
            <!-- Menu toggle button -->
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
              <i class="fa fa-bell-o"></i>
              <span class="label label-warning">10</span>
            </a>
            <ul class="dropdown-menu">
              <li class="header">You have 10 notifications</li>
              <li>
                <!-- Inner Menu: contains the notifications -->
                <ul class="menu">
                  <li><!-- start notification -->
                    <a href="#">
                      <i class="fa fa-users text-aqua"></i> 5 new members joined today
                    </a>
                  </li>
                  <!-- end notification -->
                </ul>
              </li>
              <li class="footer"><a href="#">View all</a></li>
            </ul>
          </li>
          <!-- Tasks Menu -->
          <li class="dropdown tasks-menu">
            <!-- Menu Toggle Button -->
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
              <i class="fa fa-flag-o"></i>
              <span class="label label-danger">9</span>
            </a>
            <ul class="dropdown-menu">
              <li class="header">You have 9 tasks</li>
              <li>
                <!-- Inner menu: contains the tasks -->
                <ul class="menu">
                  <li><!-- Task item -->
                    <a href="#">
                      <!-- Task title and progress text -->
                      <h3>
                        Design some buttons
                        <small class="pull-right">20%</small>
                      </h3>
                      <!-- The progress bar -->
                      <div class="progress xs">
                        <!-- Change the css width attribute to simulate progress -->
                        <div class="progress-bar progress-bar-aqua" style="width: 20%" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100">
                          <span class="sr-only">20% Complete</span>
                        </div>
                      </div>
                    </a>
                  </li>
                  <!-- end task item -->
                </ul>
              </li>
              <li class="footer">
                <a href="#">View all tasks</a>
              </li>
            </ul>
          </li>
          <!-- User Account Menu -->
          <li class="dropdown user user-menu">
            <!-- Menu Toggle Button -->
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
              <!-- The user image in the navbar-->
              <img src="/static/AdminLTE-2.3.3/dist/img/user2-160x160.jpg" class="user-image" alt="User Image">
              <!-- hidden-xs hides the username on small devices so only the image appears. -->
              <span class="hidden-xs">Alexander Pierce</span>
            </a>
            <ul class="dropdown-menu">
              <!-- The user image in the menu -->
              <li class="user-header">
                <img src="/static/AdminLTE-2.3.3/dist/img/user2-160x160.jpg" class="img-circle" alt="User Image">

                <p>
                  Alexander Pierce - Web Developer
                  <small>Member since Nov. 2012</small>
                </p>
              </li>
              <!-- Menu Body -->
              <li class="user-body">
                <div class="row">
                  <div class="col-xs-4 text-center">
                    <a href="#">Followers</a>
                  </div>
                  <div class="col-xs-4 text-center">
                    <a href="#">Sales</a>
                  </div>
                  <div class="col-xs-4 text-center">
                    <a href="#">Friends</a>
                  </div>
                </div>
                <!-- /.row -->
              </li>
              <!-- Menu Footer-->
              <li class="user-footer">
                <div class="pull-left">
                  <a href="#" class="btn btn-default btn-flat">个人中心</a>
                </div>
                <div class="pull-right">
                  <a href="/logout/" class="btn btn-default btn-flat">注销</a>
                </div>
              </li>
            </ul>
          </li>
          <!-- Control Sidebar Toggle Button -->
          <li>
            <a href="#" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a>
          </li>
        </ul>
      </div>
    </nav>
  </header>
  <!-- Left side column. contains the logo and sidebar -->
  <aside class="main-sidebar">

    <!-- sidebar: style can be found in sidebar.less -->
    <section class="sidebar">

      <!-- Sidebar user panel (optional) -->
      <div class="user-panel">
        <div class="pull-left image">
          <img src="/static/AdminLTE-2.3.3/dist/img/user2-160x160.jpg" class="img-circle" alt="User Image">
        </div>
        <div class="pull-left info">
          <p>Alexander Pierce</p>
          <!-- Status -->
          <a href="#"><i class="fa fa-circle text-success"></i> Online</a>
        </div>
      </div>

      <!-- search form (Optional) -->
      <form action="#" method="get" class="sidebar-form">
        <div class="input-group">
          <input type="text" name="q" class="form-control" placeholder="Search...">
              <span class="input-group-btn">
                <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
                </button>
              </span>
        </div>
      </form>
      <!-- /.search form -->

      <!-- Sidebar Menu -->
      <ul class="sidebar-menu">
        <li class="header">HEADER</li>
        <!-- Optionally, you can add icons to the links -->
        <li class="active"><a href="{% url "customers_list" %}"><i class="fa fa-link"></i> <span>客户信息</span></a></li>
        <li class="active"><a href="{% url "mycustomer" %}"><i class="fa fa-link"></i> <span>我的客户</span></a></li>
        <li class="active"><a href="{% url "consultrecord_list" %}"><i class="fa fa-link"></i> <span>客户跟进情况</span></a></li>
        <li class="treeview">
          <a href="#"><i class="fa fa-link"></i> <span>Multilevel</span> <i class="fa fa-angle-left pull-right"></i></a>
          <ul class="treeview-menu">
            <li><a href="#">Link in level 2</a></li>
            <li><a href="#">Link in level 2</a></li>
          </ul>
        </li>
      </ul>
      <!-- /.sidebar-menu -->
    </section>
    <!-- /.sidebar -->
  </aside>

  <!-- Content Wrapper. Contains page content -->
  {% block content %}
      <div class="content-wrapper">
          <!-- Content Header (Page header) -->
          <section class="content-header">
              <h1>
                  INDEX
                  <small>Optional description</small>
              </h1>
              <ol class="breadcrumb">
                  <li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
                  <li class="active">Here</li>
              </ol>
          </section>

          <!-- Main content -->
          <section class="content">

              <!-- Your Page Content Here -->

          </section>
          <!-- /.content -->
      </div>
  {% endblock %}
  <!-- /.content-wrapper -->

  <!-- Main Footer -->
  <footer class="main-footer">
    <!-- To the right -->
    <div class="pull-right hidden-xs">
      Anything you want
    </div>
    <!-- Default to the left -->
    <strong>Copyright &copy; 2015 <a href="#">Company</a>.</strong> All rights reserved.
  </footer>

  <!-- Control Sidebar -->
  <aside class="control-sidebar control-sidebar-dark">
    <!-- Create the tabs -->
    <ul class="nav nav-tabs nav-justified control-sidebar-tabs">
      <li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
      <li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
    </ul>
    <!-- Tab panes -->
    <div class="tab-content">
      <!-- Home tab content -->
      <div class="tab-pane active" id="control-sidebar-home-tab">
        <h3 class="control-sidebar-heading">Recent Activity</h3>
        <ul class="control-sidebar-menu">
          <li>
            <a href="">
              <i class="menu-icon fa fa-birthday-cake bg-red"></i>

              <div class="menu-info">
                <h4 class="control-sidebar-subheading">Langdon's Birthday</h4>

                <p>Will be 23 on April 24th</p>
              </div>
            </a>
          </li>
        </ul>
        <!-- /.control-sidebar-menu -->

        <h3 class="control-sidebar-heading">Tasks Progress</h3>
        <ul class="control-sidebar-menu">
          <li>
            <a href="">
              <h4 class="control-sidebar-subheading">
                Custom Template Design
                <span class="label label-danger pull-right">70%</span>
              </h4>

              <div class="progress progress-xxs">
                <div class="progress-bar progress-bar-danger" style="width: 70%"></div>
              </div>
            </a>
          </li>
        </ul>
        <!-- /.control-sidebar-menu -->

      </div>
      <!-- /.tab-pane -->
      <!-- Stats tab content -->
      <div class="tab-pane" id="control-sidebar-stats-tab">Stats Tab Content</div>
      <!-- /.tab-pane -->
      <!-- Settings tab content -->
      <div class="tab-pane" id="control-sidebar-settings-tab">
        <form method="post">
          <h3 class="control-sidebar-heading">General Settings</h3>

          <div class="form-group">
            <label class="control-sidebar-subheading">
              Report panel usage
              <input type="checkbox" class="pull-right" checked>
            </label>

            <p>
              Some information about this general settings option
            </p>
          </div>
          <!-- /.form-group -->
        </form>
      </div>
      <!-- /.tab-pane -->
    </div>
  </aside>
  <!-- /.control-sidebar -->
  <!-- Add the sidebar's background. This div must be placed
       immediately after the control sidebar -->
  <div class="control-sidebar-bg"></div>
</div>
<!-- ./wrapper -->

<!-- REQUIRED JS SCRIPTS -->

<!-- jQuery 2.2.0 -->
<script src="/static/AdminLTE-2.3.3/plugins/jQuery/jQuery-2.2.0.min.js"></script>
<!-- Bootstrap 3.3.6 -->
<script src="/static/AdminLTE-2.3.3/bootstrap/js/bootstrap.min.js"></script>
<!-- AdminLTE App -->
<script src="/static/AdminLTE-2.3.3/dist/js/app.min.js"></script>

<!-- Optionally, you can add Slimscroll and FastClick plugins.
     Both of these plugins are recommended to enhance the
     user experience. Slimscroll is required when using the
     fixed layout. -->
{% block js %}

{% endblock %}







</body>
</html>
base.html

公私客户列表展示具体代码

公户是没有销售人员

私户是有自己的销售人员

包含了模糊查询和批量处理等小功能

  # urls.py
path("customers/list/", views.CustomerView.as_view(),name="customers_list"), path("mycustomer/",views.CustomerView.as_view(),name="mycustomer"), path("customer/add/",views.AddEditCustomerView.as_view(),name="customer_add"), re_path("customer/edit/(\d+)/",views.AddEditCustomerView.as_view(),name="customer_edit"), re_path("customer/delete/(\d+)/",views.CustomerDeleteView.as_view(),name="customer_delete"),
# views.py
class
CustomerView(View): @method_decorator(login_require) def get(self,request): if reverse("customers_list") == request.path: # 根据url做分支,求不同的customer_list customer_list = Customer.objects.filter(consultant__isnull=True).order_by("-pk") # 判断字段(销售)是否为空 else: customer_list = Customer.objects.filter(consultant=request.user).order_by("-pk") # 过滤私户 # 模糊查询 field = request.GET.get("field") val = request.GET.get('val') if val: # 必须判断 q = Q() q.children.append((field + "__contains", val)) customer_list = customer_list.filter(q).order_by("-pk") # 分页展示(带有保存搜索路径) current_page_num = request.GET.get("page") count = customer_list.count() pagination = Pagination(current_page_num, count, request) customer_list = customer_list[pagination.start:pagination.end] path = request.path next = "?next=%s"%(path) # 拼路径,到后面添加和编辑成功之后,可以回到上次请求的页面,也就是从哪里来回哪里去 return render(request, "customer_list.html", {"customer_list": customer_list, "pagination": pagination,"next":next})

  # post请求是批量处理
def post(self,request): print(request.POST) # action批量处理,有操作因此发送的是post请求 func_action = request.POST.get("action") # 获取的是处理的方法 data = request.POST.getlist("select_pk_list") #传值是数组,一定要用getlist来取值,否则只能取一个 if hasattr(self,func_action): func = getattr(self,func_action) queryset = Customer.objects.filter(pk__in=data) print(queryset) ret = func(request,queryset) if ret: return ret return redirect((request.path)) # 当前路径 else: return HttpResponse("非法输入!") def patch_delete(self,request,queryset): # 批量删除 queryset.delete() def patch_change_gs(self,request,queryset): # 批量公户转私户 # 公转私更新之前需要判断一下销售是由为空,空的时候才更新,不为空就不要更新 ret = queryset.filter(consultant__isnull=True) if ret: queryset.update(consultant=request.user) else: return HttpResponse("该客户已被他人转为私户,下次请快点") def patch_change_sg(self,request,queryset): # 私户转公户 queryset.update(consultant=None) # 也可以是空字符串 ""

# views.py CustomerView

 

from django.contrib.auth.models import AbstractUser

from django.db import models
from django.contrib import auth
from django.core.exceptions import PermissionDenied
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager, User
from django.utils.translation import ugettext_lazy as _
from multiselectfield import MultiSelectField
from django.utils.safestring import mark_safe

course_choices = (('LinuxL', 'Linux中高级'),
                  ('PythonFullStack', 'Python高级全栈开发'),)

class_type_choices = (('fulltime', '脱产班',),
                      ('online', '网络班'),
                      ('weekend', '周末班',),)

source_type = (('qq', "qq群"),
               ('referral', "内部转介绍"),
               ('website', "官方网站"),
               ('baidu_ads', "百度推广"),
               ('office_direct', "直接上门"),
               ('WoM', "口碑"),
               ('public_class', "公开课"),
               ('website_luffy', "路飞官网"),
               ('others', "其它"),)

enroll_status_choices = (('signed', "已报名"),
                         ('unregistered', "未报名"),
                         ('studying', '学习中'),
                         ('paid_in_full', "学费已交齐"))

seek_status_choices = (('A', '近期无报名计划'), ('B', '1个月内报名'), ('C', '2周内报名'), ('D', '1周内报名'),
                       ('E', '定金'), ('F', '到班'), ('G', '全款'), ('H', '无效'),)
pay_type_choices = (('deposit', "订金/报名费"),
                    ('tuition', "学费"),
                    ('transfer', "转班"),
                    ('dropout', "退学"),
                    ('refund', "退款"),)

attendance_choices = (('checked', "已签到"),
                      ('vacate', "请假"),
                      ('late', "迟到"),
                      ('absence', "缺勤"),
                      ('leave_early', "早退"),)

score_choices = ((100, 'A+'),
                 (90, 'A'),
                 (85, 'B+'),
                 (80, 'B'),
                 (70, 'B-'),
                 (60, 'C+'),
                 (50, 'C'),
                 (40, 'C-'),
                 (0, ' D'),
                 (-1, 'N/A'),
                 (-100, 'COPY'),
                 (-1000, 'FAIL'),)


class UserInfo(AbstractUser):
    tel=models.CharField(max_length=32,null=True,blank=True)
    gender=models.IntegerField(choices=((1,""),(2,"")),default=1)

class Customer(models.Model):
    """
    客户表
    """
    qq = models.CharField('QQ', max_length=64, unique=True, help_text='QQ号必须唯一')
    qq_name = models.CharField('QQ昵称', max_length=64, blank=True, null=True)
    name = models.CharField('姓名', max_length=32, blank=True, null=True, help_text='学员报名后,请改为真实姓名',default="")
    sex_type = (('male', ''), ('female', ''))
    sex = models.CharField("性别", choices=sex_type, max_length=16, default='male', blank=True, null=True)
    birthday = models.DateField('出生日期', default=None, help_text="格式yyyy-mm-dd", blank=True, null=True)
    phone = models.BigIntegerField('手机号', blank=True, null=True)
    source = models.CharField('客户来源', max_length=64, choices=source_type, default='qq')
    introduce_from = models.ForeignKey('Customer', verbose_name="转介绍自学员", blank=True, null=True,on_delete=models.CASCADE)
    course = MultiSelectField("咨询课程", choices=course_choices)
    class_type = models.CharField("班级类型", max_length=64, choices=class_type_choices, default='fulltime')
    customer_note = models.TextField("客户备注", blank=True, null=True, )
    status = models.CharField("状态", choices=enroll_status_choices, max_length=64, default="unregistered",
                              help_text="选择客户此时的状态")
    date = models.DateTimeField("咨询日期", auto_now_add=True)
    last_consult_date = models.DateField("最后跟进日期", auto_now_add=True)
    next_date = models.DateField("预计再次跟进时间", blank=True, null=True)
    consultant = models.ForeignKey('UserInfo', verbose_name="销售", related_name='customers', blank=True, null=True,on_delete=models.CASCADE )
    class_list = models.ManyToManyField('ClassList', verbose_name="已报班级", )

    def __str__(self):
        return self.name+":"+self.qq


    def get_classlist(self):
        ls=[]
        for cls in self.class_list.all():
            ls.append(str(cls))
        return mark_safe("<br>".join(ls))

    def get_static_color(self):
        static_color = {
            "signed":"orange",
            "unregistered":"red",
            "studying":"blue",
            "paid_in_full":"green"
        }

        return mark_safe("<span style='background-color:%s;color:white'>%s</span>"%(static_color[self.status],self.get_status_display()))

class Campuses(models.Model):
    """
    校区表
    """
    name = models.CharField(verbose_name='校区', max_length=64)
    address = models.CharField(verbose_name='详细地址', max_length=512, blank=True, null=True)

    def __str__(self):
        return self.name

class ClassList(models.Model):
    """
    班级表
    """
    course = models.CharField("课程名称", max_length=64, choices=course_choices)
    semester = models.IntegerField("学期")
    campuses = models.ForeignKey('Campuses', verbose_name="校区",on_delete=models.CASCADE)
    price = models.IntegerField("学费", default=10000)
    memo = models.CharField('说明', blank=True, null=True, max_length=100)
    start_date = models.DateField("开班日期")
    graduate_date = models.DateField("结业日期", blank=True, null=True)
    #contract = models.ForeignKey('ContractTemplate', verbose_name="选择合同模版", blank=True, null=True,on_delete=models.CASCADE)
    teachers = models.ManyToManyField('UserInfo', verbose_name="老师")
    class_type = models.CharField(choices=class_type_choices, max_length=64, verbose_name='班额及类型', blank=True,
                                  null=True)
    class Meta:
        unique_together = ("course", "semester", 'campuses')

    def __str__(self):
        return "{}{}({})".format(self.get_course_display(), self.semester, self.campuses)
models.py
{% extends "base.html" %}

{% block content %}
    <div class="content-wrapper">
        <!-- Content Header (Page header) -->
        <section class="content-header">
            <h1>
                全部客户
                <small>所有客户信息</small>
            </h1>
            <form action="" method="get" class="pull-right">
                <ol class="breadcrumb">
                    <li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
                    <li class="active">Here</li>
                    <select name="field" id="s1" class="form-control" style="display: inline-block;width: 150px">
                        <!-- 这里最好是与数据库库中的字段相对应,方便查询-->
                        <option value="name">姓名</option>
                        <option value="qq">qq</option>
                        <option value="phone">手机</option>
                        <option value="status">状态</option>
                    </select>
                    <input type="text" name="val" class="form-control" style="display: inline-block;width: 200px">
                    <button class="btn btn-warning" style="vertical-align: 0px">search</button>
                </ol>
            </form>

        </section>

        <form action="" method="post">
            {% csrf_token %}
            <ol class="breadcrumb">
                <select name="action" id="" class="form-control" style="display: inline-block;width: 200px;">
                    <option value="">-----------------------</option>
                    <option value="patch_delete">批量删除</option>
                    <option value="patch_change_gs">公户转私户</option>
                    <option value="patch_change_sg">私转公户</option>

                </select>
                <button class="btn btn-warning" style="vertical-align: 0px;">go</button>
            </ol>

            {#列表展示#}
            <section class="content">
                <div class="row">
                    <div class="col-xs-12">
                        <div class="box">
                            <div class="box-header">
                                <h3 class="box-title">Hover Data Table</h3>
                            </div>
                            <!-- /.box-header -->
                            <div class="box-body">
                                <a href="{% url "customer_add" %}{{ next }}" class="btn btn-success btn-sm">添加客户</a>
                                <table id="example2" class="text-center table table-bordered table-hover">
                                    <thead>
                                    <tr>
                                        <th><input type="checkbox"></th>
                                        <th>编号</th>
                                        <th>客户姓名</th>
                                        <th>QQ</th>
                                        <th>手机号</th>
                                        <th>性别</th>
                                        <th>客户来源</th>
                                        <th>咨询日期</th>
                                        <th>当前状态</th>
                                        <th>销售</th>
                                        <th>所报班级</th>
                                        <th>跟进记录</th>
                                        <th>编辑</th>
                                        <th>删除</th>
                                    </tr>
                                    </thead>
                                    <tbody>

                                    {% for customer in customer_list %}
                                        <tr>
                                            {# name一样  value不一样 #}
                                            <td><input type="checkbox" name="select_pk_list" value="{{ customer.pk }}">
                                            </td>
                                            {#                                            <td><input type="checkbox" name="select_pk_list" value="{{ customer.pk }}">#}
                                            {#                                            </td>#}
                                            <td>{{ forloop.counter }}</td>
                                            <td>{{ customer.name }}</td>
                                            <td>{{ customer.qq }}</td>
                                            <td>{{ customer.phone }}</td>
                                            <td>{{ customer.get_sex_display }}</td>
                                            <td>{{ customer.get_source_display }}</td>
                                            <td>{{ customer.date|date:'Y-m-d' }}</td>
                                            <!-- 状态带有颜色、销售默认暂无、班级列表多对多 两行显示,在models中写入函数即可-->
                                            <td>{{ customer.get_static_color }}</td>
                                            <td>{{ customer.consultant|default:"暂无" }}</td>
                                            <td>{{ customer.get_classlist|default:"暂无" }}</td>
                                            <td><a href="{% url "consultrecord_list" %}?customer_id={{ customer.pk }}">跟进详情</a>
                                            </td>
                                            <td>
                                                <!-- next,携带上次的路径作为参数,以便编辑之后仍然回到上次页面   编辑、删除按钮-->
                                                <a href="{% url "customer_edit" customer.pk %}{{ next }}"><i
                                                        class="fa fa-edit" aria-hidden="true"></i></a>
                                            </td>
                                            <td><a href="{% url "customer_delete" customer.pk %}{{ next }}"><i
                                                    class="fa fa-trash-o fa-lg"></i></a></td>
                                        </tr>
                                    {% endfor %}

                                    </tbody>
                                </table>

                                <nav aria-label="Page navigation" class="pull-right">
                                    <ul class="pagination">
                                        <!-- 渲染分页标签 -->
                                        {{ pagination.page_html|safe }}
                                    </ul>
                                </nav>

                            </div>
                            <!-- /.box-body -->
                        </div>
                    </div>
                    <!-- /.col -->
                </div>
                <!-- /.row -->
            </section>


        </form>


        <!-- Main content -->

        <!-- /.content -->
    </div>
{% endblock %}




{% block js %}
    <script>

        {# 选择状态,出现下拉菜单 #}
        $("#s1").change(function () {
            if ($(this).val() === "status") {
                let s2 = `
                             <select name="q" id="s2" class="form-control" style="display: inline-block;width: 200px">
                                 <option value="signed">------------------------</option>
                                 <option value="signed">已报名</option>
                                 <option value="unregistered">未报名</option>
                                 <option value="studying">学习中</option>
                                 <option value="paid_in_full">学费已交齐</option>
                             </select>
                             `;
                $(this).next().replaceWith(s2)
            } else {
                $(this).next().replaceWith("<input type=\"text\" name=\"val\"  class=\"form-control\" style=\"display: inline-block;width: 200px\">")
            }
        })
    </script>
{% endblock %}
customer_list.html
from django import forms
class CustomerModelForm(forms.ModelForm):
    class Meta:
        model=Customer
        fields="__all__"

    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        for field in self.fields.values():
            from multiselectfield.forms.fields import MultiSelectFormField
            # 判断,排除multiselectformfield字段就不加 form-control
            if not isinstance(field,MultiSelectFormField):
                field.widget.attrs.update({'class': 'form-control'})
form.py CustomerModelForm

功能1:分页保存搜索条件

需求背景:当我们条件搜索后,我们查询下一页的数据,我们希望能够保存之前的条件。利用自定义分页。

class Pagination(object):

    def __init__(self ,current_page_num ,all_count ,request ,per_page_num=2 ,pager_count=11 ,):  # 默认参数可以改变
        """
        封装分页相关数据
        :param current_page_num: 当前访问页的数字
        :param all_count:    分页数据中的数据总条数
     :request:里面request.GET中含有get请求发送的键值对


        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数
        """
        try:
            current_page_num = int(current_page_num)
        except Exception as e:
            current_page_num = 1

        if current_page_num <1:
            current_page_num = 1

        self.current_page_num = current_page_num

        self.all_count = all_count
        self.per_page_num = per_page_num

        # 实际总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)  # 5

        # 保存搜索条件

        import copy
        self.params = copy.deepcopy(request.GET)  # {"a":"1","b":"2"}

    @property
    def start(self):
        return (self.current_page_num - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page_num * self.per_page_num

    # 该方法用于在页面渲染分页的标签按钮
    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page_num <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page_num + self.pager_count_half) > self.all_pager:

                    pager_start = self.all_pager - self.pager_count + 1
                    pager_end = self.all_pager + 1

                else:
                    pager_start = self.current_page_num - self.pager_count_half
                    pager_end = self.current_page_num + self.pager_count_half + 1

        page_html_list = []  # 存放分页标签,用于整体渲染

        # 首页
        self.params["page"] = 1  # 添加键值对,page=1

        first_page = '<li><a href="?%s">首页</a></li>' % (self.params.urlencode(),)
        page_html_list.append(first_page)

        # 上一页
        self.params["page"] = self.current_page_num - 1

        if self.current_page_num <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="?%s">上一页</a></li>' % (self.params.urlencode(),)

        page_html_list.append(prev_page)

        # 中间页
        for i in range(pager_start, pager_end):

            self.params["page"] = i

            if i == self.current_page_num:
                temp = '<li class="active"><a href="?%s">%s</a></li>' % (self.params.urlencode(), i)
            else:
                temp = '<li><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,)  # 保存搜索条件
            page_html_list.append(temp)

        # 下一页
        self.params["page"] = self.current_page_num + 1

        if self.current_page_num >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?%s">下一页</a></li>' % (self.params.urlencode(),)
        page_html_list.append(next_page)

        # 尾页
        self.params["page"] = self.all_pager

        last_page = '<li><a href="?%s">尾页</a></li>' % (self.params.urlencode(),)
        page_html_list.append(last_page)

        return ''.join(page_html_list)
page.py

功能2:模糊查询

  模糊查询实现了,输入关键字也能够查出来

 # views.py

        # 模糊查询
        field = request.GET.get("field")  # name  获取到的 name是个字符串
        val = request.GET.get('val')  # 输入的值
        if val:    # 必须判断  
            q = Q()
            q.children.append((field + "__contains", val))   # contains 包含,append里面是元组,    等价于 Q(field__contains=val)其中field为字段名,不是字符串
            customer_list = customer_list.filter(q)

 

 效果:

                     

1、Q()

  Q 查询的时候,里面含有的是 字段名=... ,现在从前端查询处获得是的字段名为字符串,直接用大Q不行,因此提供了实例化 Q()

  q = Q()

  q.children.append((字段名字符串,val值))

  queryset对象 = queryset对象.filter(q)

 

2、前端中,块标签垂直移动,可以使用vertical-align

  style="vertical-align: 3px"

功能3:批量处理

批量处理之后也是展示客户列表,因此也要写在 class CustomerView(View): 视图类中,

通过post请求可以接受 方法名 和 处理的数据记录的 id,然后根据反射 在该类中查找对应的方法进行操作。

其中包含 批量删除、私户转公户、公户转私户

 

需要注意的是,在公户转私户的过程中,如果过滤出要转换的记录之后,直接更新的话,会有bug,就是当两个用户同时公户转私户操作同一条记录 a , 如果前者将 a 转成自己的私户,后者操作的可以将 a 再次转成自己的,因此后者提交的时候同样获取了 a 的内容。因此在公户转私户之前,要对销售人员是否存在进行判断。

    def patch_change_gs(self,request,queryset):
        # 批量公户转私户
        # 公转私更新之前需要判断一下销售是由为空,空的时候才更新,不为空就不要更新

        ret = queryset.filter(consultant__isnull=True)   # 判断是否为空
        if ret:
            queryset.update(consultant=request.user)
        else:
            return HttpResponse("该客户已被他人转为私户,下次请快点")

效果:

                  

 

功能4:不同的状态显示不同的颜色

客户表中的当前状态是用 choice来写的,也就是获取文本值时候需要用到 .get_status_display

<td>{{ customer.get_status_display }}</td>

但是这样只是单纯的显示文本

需求:希望获取到的文本能够添加不同背景色,然后可以一目了然的观察每个人的状态,

 

<td>{{ customer.get_static_color }}</td>   # get_static_color 是自己在 模型类中写的方法

 

# 写在 Customer(models.Model) 中

def get_static_color(self): static_color = { "signed":"orange", "unregistered":"red", "studying":"blue", "paid_in_full":"green" } return mark_safe("<span style='background-color:%s;color:white'>%s</span>"%(static_color[self.status],self.get_status_display()))

其中:mark_safe(...)  中的 html 代码,是告诉浏览器代码是安全的,可以渲染,如果不加的话,会当做字符串显示在页面上。

 

效果:

                    

 

功能5:列表中文本两行显示(一对多关系时)

 需求:在页面展示的时候,有些字段是一对多的关系,添加的时候,有两个内容,希望能够分行展示,使得页面更加美观,这种情况类似上面的改变背景色。

<td>{{ customer.get_classlist|default:"暂无" }}</td>   # 班级列表是一对多,可以有多个

 在 Customer(models.Model)  模型类中添加函数:

    def get_classlist(self):
        ls=[]
        for cls in self.class_list.all():
            ls.append(str(cls))
        return mark_safe("<br>".join(ls))

 

客户的增删改查

具体的实现代码:

# urls.py

    path("customer/add/",views.AddEditCustomerView.as_view(),name="customer_add"),
    re_path("customer/edit/(\d+)/",views.AddEditCustomerView.as_view(),name="customer_edit"),
    re_path("customer/delete/(\d+)/",views.CustomerDeleteView.as_view(),name="customer_delete"),

# views.py

class AddCustomerView(View):

    @method_decorator(login_require)
    def get(self,request):
        form = CustomerModelForm()
        return render(request,"customer_add.html",{"form":form})

    def post(self,request):

        form = CustomerModelForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect(reverse("customers_list"))
        else:
            return render(request,"customer_add.html",{"form":form})


class CustomerEditView(View):

    @method_decorator(login_require2)
    def get(self,request,edit_id):
        # customer_obj = Customer.objects.filter(pk=edit_id)  #用filter是错误的,
        customer_obj = Customer.objects.get(pk=edit_id)  # get 只能取到一个对象,非queryset对象
        form = CustomerModelForm(instance=customer_obj)
        # path用于取消的时候走的路径
        path= request.GET.get("next")
        return render(request,"customer_edit.html",{"path":path,"form":form,"request":request})

    def post(self,request,edit_id):
        customer_obj = Customer.objects.get(pk=edit_id)
        form = CustomerModelForm(request.POST,instance=customer_obj)
        if form.is_valid():
            form.save()
            return redirect(request.GET.get("next"))
        else:
            return render(request,"customer_edit.html",{"form":form})


class CustomerDeleteView(View):

    @method_decorator(login_require2)
    def get(self,request,del_id):
        customer_obj = Customer.objects.filter(pk=del_id).delete()
        print(request.GET.get("next"))
        # 回到上次访问的url  展示(全部或我的)
        return redirect(request.GET.get("next"))

# html

{% extends "base.html" %}

{% block content %}

    <div class="content-wrapper">
        <!-- Content Header (Page header) -->
        <section class="content-header" style="text-align: center">
            <h2>添加客户
                <small>填写客户详细信息</small>
            </h2>
            <ol class="breadcrumb">
                <li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
                <li class="active">Here</li>
            </ol>
        </section>

        <!-- Main content -->
        <section class="content">

            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <form action="" method="post" novalidate>
                        {% csrf_token %}
                        {% for field in form %}
                            <div class="form-group">
                                <label for="">{{ field.label }}</label>
                                {{ field }}
                                <span class="error">{{ field.errors.0 }}</span>
                            </div>
                        {% endfor %}
                        <a href="" class="btn btn-default">取消</a>&nbsp;&nbsp;&nbsp;
                        <button class="btn btn-default">确认</button>

                    </form>
                </div>
            </div>
        </section>
        <!-- /.content -->
    </div>
{% endblock %}
customer_add.html
{% extends "base.html" %}

{% block content %}

    <div class="content-wrapper">
        <!-- Content Header (Page header) -->
        <section class="content-header" style="text-align: center">
            <h2>修改客户
                <small>填写客户详细信息</small>
            </h2>
            <ol class="breadcrumb">
                <li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
                <li class="active">Here</li>
            </ol>
        </section>

        <!-- Main content -->
        <section class="content">

            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <form action="" method="post" novalidate>
                        {% csrf_token %}
                        {% for field in form %}
                            <div class="form-group">
                                <label for="">{{ field.label }}</label>
                                {{ field }}
                                <span class="error">{{ field.errors.0 }}</span>
                            </div>
                        {% endfor %}
                        <a href="{{ path }}" class="btn btn-default">取消</a>&nbsp;&nbsp;&nbsp;
                        <button class="btn btn-default">确认</button>

                    </form>
                </div>
            </div>
        </section>
        <!-- /.content -->
    </div>
{% endblock %}
customer_edit.html

优化后的代码:

由于添加和编辑无论就后台还是前台代码都有很多的重复,因此需要进行优化,将添加和编辑合二为一,由于添加的时候参数只有request, 编辑的时候还多了 edit_id 的参数,因此,需要给的参数是默认值,

# 优化后,添加的时候edit_id为空,编辑的时候有值
class
AddEditCustomerView(View): def get(self,request,edit_id=None): # customer_obj = Customer.objects.get(pk=edit_id) # 错误的,用get(没有值会报错) customer_obj = Customer.objects.filter(pk=edit_id).first() # modelform 和 form 校验的时候里面的参数传的是对象,并非queryset类型 form = CustomerModelForm(instance=customer_obj) # 取消的时候传的路径 path = request.GET.get("next") return render(request,"customer_add_edit.html",{"form":form,"path":path,"customer_obj":customer_obj}) def post(self,request,edit_id=None): customer_obj = Customer.objects.filter(pk=edit_id).first() form = CustomerModelForm(request.POST,instance=customer_obj) if form.is_valid(): form.save() return redirect(request.GET.get("next")) else: return render(request,"customer_add_edit.html",{"form":form,"customer_obj":customer_obj})

 

{% extends "base.html" %}

{% block content %}

    <div class="content-wrapper">
        <!-- Content Header (Page header) -->
        <section class="content-header" style="text-align: center">
            <h2>
                {% if not customer_obj %}
                    添加客户信息
                    {% else %}
                    修改客户信息
                {% endif %}
            </h2>
            <ol class="breadcrumb">
                <li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
                <li class="active">Here</li>
            </ol>
        </section>
        <!-- Main content -->
        <section class="content">

            <div class="row">
                <div class="col-md-8 col-md-offset-2">

                    <form action="" method="post" novalidate>
                        {% csrf_token %}
                        {% for field in form %}
                            <div class="form-group">
                                <label for="">{{ field.label }}</label>
                                {{ field }}
                                <span class="error">{{ field.errors.0 }}</span>
                            </div>
                        {% endfor %}
                        <a href="{{ path }}" class="btn btn-default">取消</a>&nbsp;&nbsp;&nbsp;
                        <button class="btn btn-default">确认</button>

                    </form>
                </div>
            </div>
        </section>
        <!-- /.content -->
    </div>
{% endblock %}
customer_add_edit.html

总结1:携带上次请求路径,?next=/.../

?next=/customer/list/  、 ?next=/mycustomer/

由于客户的列表展示中分为公户和私户,在不同的界面打开添加和编辑成功后,应该回到原来展示的界面,这里由于是公户和私户两条线都有编辑和添加功能,因此重定向的时候是不能写死的,所以要在发送添加和编辑请求的时候,携带上次请求的路径,作为参数,也就是 ?next=/.../

从哪里来回哪里去

思路:在展示的视图函数(get请求)中,要获取到路径进行拼接,在添加和编辑按钮的 请求路径中添加参数

  获取next路径

path = request.path 
next = "?next=%s"%(path)   # 拼路径,到后面添加和编辑成功之后,可以回到上次请求的页面,也就是从哪里来回哪里去   render给页面

   编辑和删除按钮的请求路径

<td>
    <!-- next,携带上次的路径作为参数,以便编辑之后仍然回到上次页面   编辑、删除按钮-->
    <a href="{% url "customer_edit" customer.pk %}{{ next }}"><i class="fa fa-edit" aria-hidden="true"></i></a>     # 其中i是图标,customer.pk是反向解析的动态传参  
</td>
<td>
    <a href="{% url "customer_delete" customer.pk %}{{ next }}"><i class="fa fa-trash-o fa-lg"></i></a>    
</td>

 

跟进记录情况

跟进记录的展示、添加、编辑和客户列表是类似的,只是这里不再分公户和私户两条线,这里应该都是私户的,显示的是当前登录用户的客户的跟进情况

展示、添加、编辑 具体实现代码:

 # urls.py

    path("consultrecord/list/",views.ConsultRecordView.as_view(),name="consultrecord_list"),
    re_path("consultrecord/add/",views.AddEditConsultRecordView.as_view(),name="consultrecord_add"),
    re_path("consultrecord/edit/(\d+)/",views.AddEditConsultRecordView.as_view(),name="consultrecord_edit"),
    re_path("consultrecord/delete/(\d+)/",views.ConsultRecordDeleteView.as_view(),name="consultrecord_delete")

# views.py   添加和编辑是优化的代码

class ConsultRecordView(View):

    @method_decorator(login_require)
    def get(self,request):
        consultrecord_list = ConsultRecord.objects.filter(consultant=request.user)

        customer_id = request.GET.get("customer_id")
        if customer_id:
            consultrecord_list = ConsultRecord.objects.filter(customer_id=customer_id)

        # 分页
        current_page_num = request.GET.get("page",1)
        pagination = Pagination(current_page_num,consultrecord_list.count(),request)
        consultrecord_list = consultrecord_list[pagination.start:pagination.end]

        path = request.path
        next = "?next=%s"%(path)

        return render(request,"consultrecord_list.html",{"next":next,"consultrecord_list":consultrecord_list,"pagination":pagination})


class AddEditConsultRecordView(View):

    def get(self,request,edit_id=None):
        consultrecord_obj = ConsultRecord.objects.filter(pk=edit_id).first()
        form = ConsultrecordModelForm(instance=consultrecord_obj)
        path = request.GET.get("next")
        return render(request,"consultrecord_add_edit.html",{"form":form,"path":path,"consultrecord_obj":consultrecord_obj})

    def post(self,request,edit_id=None):
        consultrecord_obj = ConsultRecord.objects.filter(pk=edit_id).first()
        form = ConsultrecordModelForm(request.POST,instance=consultrecord_obj)
        if form.is_valid():
            form.save()
            return redirect(reverse("consultrecord_list"))  # 跟进记录
        else:
            return render(request,"consultrecord_add_edit.html",{"form":form,"consultrecord_obj":consultrecord_obj})


class ConsultRecordDeleteView(View):

    def get(self,request,del_id):
        consultrecord_obj = ConsultRecord.objects.filter(pk=del_id).delete()
        print(request.GET.get("next"))
        return redirect(request.GET.get("next"))
View Code

# html

{% extends "base.html" %}

{% block content %}
    <div class="content-wrapper">
        <!-- Content Header (Page header) -->
        <section class="content-header">
            <h1>
                客户跟进记录
                <small>跟进记录信息</small>
            </h1>
        </section>

        {#列表展示#}
        <section class="content">
            <div class="row">
                <div class="col-xs-12">
                    <div class="box">
                        <div class="box-header">
                            <h3 class="box-title">Hover Data Table</h3>
                        </div>
                        <!-- /.box-header -->
                        <div class="box-body">
                            <a href="{% url "consultrecord_add" %}{{ next }}"
                               class="btn btn-success btn-sm">添加客户跟进信息</a>
                            <table id="example2" class="text-center table table-bordered table-hover">
                                <thead>
                                <tr>
                                    <th>编号</th>
                                    <th>客户姓名</th>
                                    <th>当前状态</th>
                                    <th>跟进内容</th>
                                    <th>跟进人</th>
                                    <th>编辑</th>
                                    <th>删除</th>
                                </tr>
                                </thead>
                                <tbody>
                                {% for consultrecord in consultrecord_list %}
                                    <tr>
                                        <td>{{ forloop.counter }}</td>
                                        <td>{{ consultrecord.customer.name }}</td>
                                        <td>{{ consultrecord.get_status_display }}</td>
                                        <td>{{ consultrecord.note }}</td>
                                        <td>{{ consultrecord.consultant }}</td>
                                        <td>
                                            <!-- next,携带上次的路径作为参数,以便编辑之后仍然回到上次页面  编辑、删除按钮-->
                                            <a href="{% url "consultrecord_edit" consultrecord.pk %}{{ next }}"><i
                                                    class="fa fa-edit" aria-hidden="true"></i></a>
                                        </td>
                                        <td><a href="{% url "consultrecord_delete" consultrecord.pk %}{{ next }}"><i
                                                class="fa fa-trash-o fa-lg"></i></a></td>
                                    </tr>
                                {% endfor %}

                                </tbody>
                            </table>

                            <nav aria-label="Page navigation" class="pull-right">
                                <ul class="pagination">
                                    {# 渲染分页标签 #}
                                    {{ pagination.page_html|safe }}
                                </ul>
                            </nav>

                        </div>
                        <!-- /.box-body -->
                    </div>
                </div>
                <!-- /.col -->
            </div>
            <!-- /.row -->
        </section>

    </div>
{% endblock %}

{% block js %}

{% endblock %}
consultrecord_list.html
{% extends "base.html" %}

{% block content %}

    <div class="content-wrapper">
        <!-- Content Header (Page header) -->
        <section class="content-header" style="text-align: center">
            <h2>
                {% if not consultrecord_obj %}
                    添加跟进记录信息
                {% else %}
                    修改跟进记录信息
                {% endif %}
            </h2>
            <ol class="breadcrumb">
                <li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
                <li class="active">Here</li>
            </ol>
        </section>
        <!-- Main content -->
        <section class="content">

            <div class="row">
                <div class="col-md-8 col-md-offset-2">

                    <form action="" method="post" novalidate>
                        {% csrf_token %}
                        {% for field in form %}
                            <div class="form-group">
                                <label for="">{{ field.label }}</label>
                                {{ field }}
                                <span class="error">{{ field.errors.0 }}</span>
                            </div>
                        {% endfor %}
                        <a href="{{ path }}" class="btn btn-default">取消</a>&nbsp;&nbsp;&nbsp;
                        <button class="btn btn-default">确认</button>

                    </form>
                </div>
            </div>
        </section>
        <!-- /.content -->
    </div>
{% endblock %}
consultrecord_add_edit.html

效果:

  显示的跟进情况都是当前登录用户 chen 的私户,并且一个私户可以有多条跟进记录

                 

功能1:客户列表展示中添加跟进详情

需求:希望能够在客户展示界面有一个 跟进详情 的操作,点开之后,只显示,该私户的跟进详情。

  customer_list.html 在客户列表展示中添加 跟进详情的标签,点击添加跟进详情的,将该记录的pk值作为参数传给后台。

 <td><a href="{% url "consultrecord_list" %}?customer_id={{ customer.pk }}">跟进详情</a></td>

 

class ConsultRecordView(View):

    @method_decorator(login_require)
    def get(self,request):
        consultrecord_list = ConsultRecord.objects.filter(consultant=request.user)   # 左侧栏点击的时候不存在参数

        # 判断是否存在参数id
        customer_id = request.GET.get("customer_id")    # a标签点击的时候存在参数
        if customer_id:
            consultrecord_list = ConsultRecord.objects.filter(customer_id=customer_id)

        # 分页
        current_page_num = request.GET.get("page",1)
        pagination = Pagination(current_page_num,consultrecord_list.count(),request)
        consultrecord_list = consultrecord_list[pagination.start:pagination.end]

        path = request.path
        next = "?next=%s"%(path)

        return render(request,"consultrecord_list.html",{"next":next,"consultrecord_list":consultrecord_list,"pagination":pagination})

 效果:

  在客户界面点击跟进详情会只出现,该客户的跟进详情,若是在左侧栏点击客户跟进详情,那么会显示当前用户所有客户的跟进详情。

                    

                   

 

posted @ 2018-11-12 21:45  葡萄想柠檬  Views(326)  Comments(0)    收藏  举报
目录代码