当前位置:   article > 正文

Django实战【四】—客户管理模块代码实现_django客户管理系统源码

django客户管理系统源码

一、客户管理系统增删改查

1.业务回顾

大家还记得我们项目的三大块吧,第一个就是客户管理。

客户管理系统是提供给网咨、销售人员来查看客户信息、增加客户、修改客户信息的。当然客户在我们项目中还有公户和私户的区别,公户私户实际是由销售总监根据销售的业务能力来合理分配,从而使客户转化率最大化。

销售人员通过分配到的客户,存放在自己的私户中,通过不断的跟进,交流,让客户报名。期间的跟进记录我们应当都存入数据库,以便以后的继续跟进。

由于该博客仅用于知识点的分享实现,所以我们这里只实现一个完整的功能块,其他类似的就不展示了,所以我们这里只实现客户的信息增删改查,也就是customer应用下的客户数据。

2.公共客户数据的增删改查url

项目下urls路由分发对应的请求到customer应用下

url(r'^customer/', include("customer.urls")),
  • 1

customer应用下的增删改查url

from django.conf.urls import url
from customer.views import customer

urlpatterns = [
    # 公户数据展示url
    url(r'^common/list', customer.CommonList.as_view(), name="common_list"),
    # 公户信息添加url
    url(r'^common/add/', customer.CommonAdd.as_view(), name="common_add"),
    # 公户信息修改url
    url(r'^common/edit/(\d+)/', customer.CommonEdit.as_view(), name="common_edit"),
    # 公户信息删除
    url(r'^common/del/(\d+)/', customer.CommonDel.as_view(), name="common_del"),
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3.公户数据的展示视图和模板

关于客户信息的相关视图我们放在customer下的views文件夹下的customer.py中。

公户信息展示几点注意点:

  • 在客户数据展示的视图中我们使用了django自带的auth认证装饰器,装饰器在验证失败后会跳转login页面,但是django默认配置的跳转login页面url并不是我们想要的,需要我们在settings中配置一下。
# 配置登录认证失败跳转的页面
LOGIN_URL = '/crmweb/login/'
  • 1
  • 2
  • 在数据展示页面中,还使用了自定义分页,自定义分页博客中有,就不详述了,想要查看点这里:Django框架—分页器paginator 过滤器部分
公户展示视图写法

公户信息展示中实现了两个额外功能

  • 查询功能

查询功能的实现,是基于form表单通过get提交select框和input框,select框用来提交查询的条件,input框提交查询的查询参数。

后端从get请求中获取前端参数,根据select提交的值来确定通过什么字段来查询,根据input的值来确定查询条件。

<form action="" method="get" class="navbar-form navbar-left">
                        <div class="input-group">
                            <div class="input-group-btn btn-info">
                                <select name="condition" id="search" class="btn input-group-sm btn-info"
                                        style="border: 0">
                                    <option value="" readonly>条件</option>
                                    <option value="qq_name">昵称</option>
                                    <option value="qq">QQ号</option>
                                </select>
                            </div>
                            <input type="text" name="q" class="form-control" placeholder="Search...">
                            <span class="input-group-btn">
                                <button type="submit" id="search-btn" class="btn btn-flat">
                                    <i class="fa fa-search"></i>
                                </button>
                            </span>
                        </div>
                    </form>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 批量操作功能

批量操作功能的实现,也是通过form表单post请求提交数据,在类中定义一系列批量操作的方法。

根据前端select提交的option选项中的value值,也就是字符串来反射类中的批量操作方法,根据表格中提交的记录id来批量修改。

from django import views
from customer import models
from django.db.models import Q, Count
from django.shortcuts import (
    render, redirect, reverse, HttpResponse
)
from customer.forms import formAuth
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from utils.customPaginator import Paginator


# 公户数据展示
class CommonList(views.View):
    @method_decorator(login_required)  # 装饰器函数验证是否登录
    def dispatch(self, request, *args, **kwargs):
        res = super().dispatch(request, *args, **kwargs)
        return res

    def get(self, request):
        # 查询公户全部数据
        all_customers = models.Customer.objects.filter(consultant__isnull=True, status="unregistered").order_by(
            "-pk")

        # 使用Q查询拼接查询条件
        condition = request.GET.get("condition", "")  # 获取搜索的条件分类
        query = request.GET.get("q", "")  # 获取搜索的条件
        if condition and query:  # 如果有查询调参数,两个参数都有,根据查询参数查询后找到数据
            condition = condition + "__contains"
            q = Q()  # Q实例化生成q对象,q对象可以帮我们拼接字符串为 condition__contians= xx的关键字参数传到filter中。
            q.children.append((condition, query))
            all_customers = all_customers.filter(q)

        # 开始分页展示
        data_counts = all_customers.count()  # 获取分页的总数据数量

        # 生成一个分页对象
        paginator = Paginator(request, data_counts, 10)

        # 获取当前页展示数据的范围
        try:  # 异常是否查到了数据,查到了才切片,不然会报错
            all_customers = all_customers[paginator.start:paginator.end]
        except Exception:
            pass

        # 获取分页的标签
        paginator_tag = paginator.paginate()  # 调用定义好的分页方法

        # 获取跳转页的标签
        jump_tag = paginator.jump_page()  # 调用定义好的跳转页方法获取跳转页标签
        jump_js = paginator.jump_js()  # 调用定义好的跳转页方法获取跳转页js代码

        # fixme 这里我实现的用户被选走的提示方式有点low,暂时先这样吧,而且在实际业务中,公户转私户应该是由销售总监分配的,而不是比谁先抢到。
        name_str = None
        # 客户被选走的错误提示
        if "*customer*" in request.path:
            name_list = request.path.split("*customer*")[1:]
            name_str = ','.join(name_list)
        
        # 返回response对象,以及需要渲染的数据
        return render(request, "common_list.html",{"all_customers": all_customers, "paginator_tag": paginator_tag,"jump_tag": jump_tag, "jump_js": jump_js, "name_str": name_str})

    def post(self, request):
        operate = request.POST.get("operate")  # 获取用户提交的批量操作类型
        if operate:
            # 如果有,去反射类中对应的批量操作方法
            if hasattr(self, operate):
                func = getattr(self, operate)
                if callable(func):
                    ret = func(request)  # 执行批量操作方法
                    if ret:  # 函数有返回值,也就是有被别的销售提前选走的客户
                        info = ""
                        for obj in ret:
                            # fixme 客户被任选走,在前端提示哪些客户被选走,这里我放在路径中,并不太好,目前就这样实现,以后有更好的办法再更新
                            info = info + "*customer*" + obj.__str__()
                        url = request.path + info  # 拼接url,携带提示信息
                        return redirect(url)
                    return redirect(request.path)
                else:
                    return HttpResponse("访问连接有误!")
            return HttpResponse("访问连接有误!")
        return redirect("common")

    def batch_delete(self, request, *args, **kwargs):
        """批量删除客户"""
        # 实际工作场景中并不是真的删除,而是修改该条数据在数据库的修改状态
        choose_list = request.POST.getlist("choose")
        models.Customer.objects.filter(pk__in=choose_list).delete()

    def batch_update(self, request, *args, **kwargs):
        """批量更新客户状态"""
        choose_list = request.POST.getlist("choose")
        models.Customer.objects.filter(pk__in=choose_list).update(status="studying")

    def batch_c2p(self, request, *args, **kwargs):
        """批量公户转私户操作"""
        choose_list = request.POST.getlist("choose")  # 获取选中的客户id,注意通过getlist来获取,获取一个列表
        customer_list = models.Customer.objects.filter(pk__in=choose_list)  # 根据客户id查到客户

        has_choosed = []  # 定义一个列表
        for customer_obj in customer_list:
            if customer_obj.consultant:  # 如果客户被别人选了,放到已选列表
                has_choosed.append(customer_obj)
            else:
                # 如果还没有备选则选择并保存
                customer_obj.consultant = request.user
                customer_obj.save()  # 通过save方法保存到数据库
        return has_choosed  # 返回已经被选择的用户

公户展示及批量操作视图
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
base.html

我们之前说过项目模板是用的开源的模板,这里我们是使用一个base页面,其他页面结构相同的都来继承这个base页面。

话说还记得模板继承的用法把,这里简单回顾:

先提取公共页面到一个base.html文件中,对于需要根据具体页面内容个性化定制的地方,使用block块来包裹,block块尽量多。

在继承的页面中,通过extends来继承base页面,对于需要自己定制的部分,在block中写入自己的内容。

{% load static %}
<!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>AliCRM</title>
    {% block head %}
        <!-- 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">
        <link rel="stylesheet" href="{% static 'adminlte/bower_components/bootstrap/dist/css/bootstrap.min.css' %}">
        <!-- Font Awesome -->
        <link rel="stylesheet" href="{% static 'adminlte/bower_components/font-awesome/css/font-awesome.min.css' %}">
        <!-- Ionicons -->
        <link rel="stylesheet" href="{% static 'adminlte/bower_components/Ionicons/css/ionicons.min.css' %}">
        <!-- Theme style -->
        <link rel="stylesheet" href="{% static 'adminlte/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/dist/css/skins/skin-blue.min.css' %}">
    {% endblock head %}

</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="" class="logo">
            <!-- mini logo for sidebar mini 50x50 pixels -->
            <span class="logo-mini"><b>A</b>li</span>
            <!-- logo for regular state and mobile devices -->
            <span class="logo-lg"><b>Ali</b>CRM</span>
        </a>

        <!-- Header Navbar -->
        <nav class="navbar navbar-static-top" role="navigation">
            <!-- Sidebar toggle button-->
            <a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
                <span class="sr-only">Toggle navigation</span>
            </a>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse pull-left" id="navbar-collapse">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
                    <li><a href="#">Link</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu" role="menu">
                            <li><a href="#">Action</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                            <li class="divider"></li>
                            <li><a href="#">One more separated link</a></li>
                        </ul>
                    </li>
                </ul>
            </div>

            <!-- 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/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/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">{{ request.user.username }}</span>
                        </a>
                        <ul class="dropdown-menu">
                            <!-- The user image in the menu -->
                            <li class="user-header">
                                <img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="img-circle"
                                     alt="User Image">

                                <p>
                                    {{ request.user.username }} - 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">Profile</a>
                                </div>
                                <div class="pull-right">
                                    <a href="" class="btn btn-default btn-flat">Sign out</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 sidebar -->
    <aside class="main-sidebar">
        <!-- sidebar: style can be found in sidebar.less -->
        <section class="sidebar">
            <!-- Sidebar user panel -->
            <div class="user-panel">
                <div class="pull-left image">
                    <img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="img-circle" alt="User Image">
                </div>
                <div class="pull-left info">
                    <p>{{ request.user.username }}</p>
                    <a href="#"><i class="fa fa-circle text-success"></i> Online</a>
                </div>
            </div>
            <!-- search form -->
            <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: : style can be found in sidebar.less -->
            <ul class="sidebar-menu" data-widget="tree">
                <li class="header">操作菜单</li>

                <li>
                    <a href="{% url 'common_list' %}">
                        <i class="fa fa-cubes"></i>
                        <span>公户信息展示</span>
                        <span class="pull-right-container"></span>
                    </a>
                </li>

            </ul>
        </section>
        <!-- /.sidebar -->
    </aside>

    <!-- Content Wrapper. Contains page content -->
    <div class="content-wrapper">
        <!-- Content Header (Page header) -->
        <section class="content-header">
            <h1>
                {% block title %}
                    Title
                {% endblock title %}
                <small>Developer Ryxiong</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 container-fluid">

            <!--------------------------
              | Your Page Content Here |
              -------------------------->
            {% block content %}
                Content
            {% endblock content %}

        </section>
        <!-- /.content -->
    </div>
    <!-- /.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 © 2016 <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="javascript:;">
                            <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="javascript:;">
                            <h4 class="control-sidebar-subheading">
                                Custom Template Design
                                <span class="pull-right-container">
                    <span class="label label-danger pull-right">70%</span>
                  </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 -->

{% block js %}
    <!-- REQUIRED JS SCRIPTS -->

    <!-- jQuery 3 -->
    <script src="{% static 'jquery/jquery-3.4.1.js' %}"></script>
    <!-- Bootstrap 3.3.7 -->
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
    <!-- AdminLTE App -->
    <script src="{% static 'adminlte/dist/js/adminlte.min.js' %}"></script>

    <!-- Optionally, you can add Slimscroll and FastClick plugins.
         Both of these plugins are recommended to enhance the
         user experience. -->
{% endblock js %}

{% block customjs %}

{% endblock customjs %}

</body>
</html>

base.html
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
公户信息展示html

公户信息展示继承base页面

{% extends 'BASE.html' %}
{% load static %}
{% block head %}
    {{ block.super }}
{% endblock head %}
{% block title %}
        公户信息展示
{% endblock title %}
{% block content %}
    <div class="row">
        <div class="col-xs-12">
            <div class="box">
                <div class="box-header">
                    <h3 class="box-title"></h3>
                    <form action="" method="get" class="navbar-form navbar-left">
                        <div class="input-group">
                            <div class="input-group-btn btn-info">
                                <select name="condition" id="search" class="btn input-group-sm btn-info"
                                        style="border: 0">
                                    <option value="" readonly>条件</option>
                                    <option value="qq_name">昵称</option>
                                    <option value="qq">QQ号</option>
                                </select>
                            </div>
                            <input type="text" name="q" class="form-control" placeholder="Search...">
                            <span class="input-group-btn">
                                <button type="submit" id="search-btn" class="btn btn-flat">
                                    <i class="fa fa-search"></i>
                                </button>
                            </span>
                        </div>
                    </form>
                    <a href="{% url 'common_add' %}" class="btn btn-primary pull-right">新增客户</a>

                </div>
                <div class="box-body">
                    <div class="row">
                        <div class="col-sm-6">
                        </div>
                    </div>
                    <form action="" method="post">
                        {% csrf_token %}
                        <div class="input-group" style="width: 220px;margin-bottom: 5px;margin-left: 15px">
                            <select name="operate" id="operate" class="form-control btn-default">
                                <option value="">选择批量操作</option>
                                <option value="batch_delete">批量删除</option>
                                <option value="batch_update">批量更改客户状态</option>
                                {% if flag %}
                                    <option value="batch_c2p">批量公转私</option>
                                {% else %}
                                    <option value="batch_c2p">批量公转私</option>
                                {% endif %}
                            </select>
                            <span class="input-group-btn">
                                <button type="submit" class="btn btn-warning btn-flat">Go!</button>
                            </span>
                        </div>
                        {% if name_str %}
                            <div class="btn text-danger" id="choose_error">顾客:{{ name_str }}已经被选走了</div>
                        {% endif %}


                        <table id="example2" class="table table-bordered table-hover text-center">
                            <thead>
                            <tr>
                                <th style="width: 6%">
                                    <span>
                                        <i class="fa fa-check-square-o"></i>
                                        <input type="checkbox" name="batch_choose">
                                    </span>
                                </th>
                                <th style="width: 5%">序号</th>
                                <th>qq</th>
                                <th>姓名</th>
                                <th>电话</th>
                                <th>来源</th>
                                <th>咨询课程</th>
                                <th>客户状态</th>
                                <th>销售老师</th>
                                <th>操作</th>

                            </tr>
                            </thead>
                            <tbody>
                            {% for customer in all_customers %}
                                <tr>
                                    <td><input type="checkbox" name="choose" value="{{ customer.pk }}"></td>
                                    <td>{{ forloop.counter }}</td>
                                    <td>{{ customer.qq }}</td>
                                    <td>{{ customer.qq_name }}</td>
                                    <td>
                                        {{ customer.phone|default:"暂无" }}
                                    </td>
                                    <td>{{ customer.get_source_display|default:'暂无' }}</td>
                                    <td>{{ customer.get_course_display|default:"暂无" }}</td>
                                    <td>{{ customer.get_status_display }}</td>
                                    <td>{{ customer.consultant.username|default:'暂无' }}</td>
                                    <td>
                                        <a style="color: #00c3cc;" href="{% url 'common_edit' customer.pk %}">
                                            <i class="fa fa-edit" aria-hidden="true"></i>
                                        </a>
                                        |
                                        <a style="color: #d9534f;" href="{% url 'common_del' customer.pk %}">
                                            <i class="fa fa-trash-o"></i>
                                        </a>
                                    </td>
                                </tr>
                            {% endfor %}

                            </tbody>
                            <tfoot>
                            </tfoot>
                        </table>
                        {% if not all_customers %}
                            <h3 class="text-center">没有相关记录!</h3>
                        {% endif %}
                    </form>


                    <div class="pull-right" style="display:inline-block; width: 120px;margin: 22px 10px">
                        {{ jump_tag|safe }}
                    </div>

                    <div class="pull-right">
                        {{ paginator_tag|safe }}
                    </div>


                </div>
                <!-- /.box-body -->
            </div>
            <!-- /.box -->
        </div>
        <!-- /.col -->
    </div>
{% endblock content %}
{% block js %}
    {{ block.super }}
{% endblock js %}

{% block customjs %}
    <script>
        $("[name=batch_choose]").click(function () {
            var status = $(this).prop("checked");
            $("[name=choose]").prop('checked', status)
        });
        $("#choose_error").click(function () {
            $("#choose_error").css("display", "none");
        })
    </script>
    {{ jump_js|safe }}
{% endblock customjs %}

common_list.html
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154

实现后的页面效果

img

4.添加公户数据的视图和模板

添加公户视图函数

公户数据的添加,我们这里是通过modelform组件写的,所以先在customer应用下forms文件夹下formAuth.py中定义一个ModelForm。

from django import forms
from customer import models


# 顾客添加form认证
class CustomerAddMF(forms.ModelForm):
    # 定义添加数据使用的ModelForm
    class Meta:
        model = models.Customer  # 指定一张表
        fields = "__all__"  # 指定字段,排除用exclude

    def __init__(self,*args,**kwargs):
        """重写init方法,批量添加标签样式"""
        super().__init__(*args,**kwargs)  # 执行父类的init方法,必须
        for field in self.fields:
            if field != "course":  # 课程是多选框,不设置标签样式
                self.fields[field].widget.attrs.update({"class":"forms-control",})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

添加公户视图写法:

添加公户是通过modelform来实现的,get请求根据modeform实例化对象,返回前端,前端遍历对象来生成标签。post请求根据后端提交的数据给modelform去实例化,然后验证数据合法性,合法后才写入数据库。

# 添加公共客户记录
class CommonAdd(views.View):
    """添加公户记录视图"""
    @method_decorator(login_required)  # 登录验证
    def dispatch(self, request, *args, **kwargs):
        res = super().dispatch(request, *args, **kwargs)
        return res

    def get(self, request):
        form_obj = formAuth.CustomerAddMF()  # 通过modelform实例化生成对象
        return render(request, "common_add.html", {"form_obj": form_obj})

    def post(self, request):
        # 实例化modelform并传入前端提交的数据
        form_obj = formAuth.CustomerAddMF(request.POST)
        if form_obj.is_valid():  # 对提交数据验证
            form_obj.save()  # 合法保存到数据库
            return redirect("common_list")
        else:
            # 不合法将原有数据返回给页面,并显示错误提示
            return render(request, "common_add.html", {"form_obj": form_obj})

添加公户视图
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

添加公户html文件

{% extends 'BASE.html' %}
{% block head %}
    {{ block.super }}
{% endblock head %}
{% block title %}
    新增客户
{% endblock title %}
{% block content %}
    <div class="container-fluid">
        <div class="row">
            <div class="col-sm-7">
                <form action="" method="post" class="form-horizontal" novalidate>
            {% csrf_token %}
                    {% for field in form_obj %}
                        <div class="form-group">
                            <label for="{{ field.id_for_label }}" class="control-label col-sm-2">{{ field.label }}</label>
                            <div class="col-sm-8">
                                {{ field }}
                                <span class="text-danger">{{ field.errors.0 }}</span>
                            </div>
                        </div>
                    {% endfor %}
                    <input type="submit" class="btn btn-success pull-right" value="添加">
                </form>
            </div>
        </div>
    </div>

{% endblock content %}
{% block js %}
    {{ block.super }}
{% endblock js %}

common_add.html
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

5.编辑客户的视图和模板

编辑客户视图写法
# 修改公共客户记录
class CommonEdit(views.View):
    @method_decorator(login_required)  # 登录验证状态
    def dispatch(self, request, *args, **kwargs):
        res = super().dispatch(request, *args, **kwargs)
        return res

    def get(self, request, n):
        """
        get请求,展示修改页面,其中展示原始数据
        :param request: request请求
        :param n: 前端传递过来的记录id
        :return: 返回response对象
        """
        customer_obj = models.Customer.objects.filter(pk=n).first()  # 找到需要修改的客户对象
        form_obj = formAuth.CustomerAddMF(instance=customer_obj)  # 通过modelform实例化的instance参数指定一个客户对象,可以在前端页面中直接渲染原始数据。
        return render(request, "common_add.html", {"form_obj": form_obj})

    def post(self, request, n):
        """修改客户记录post请求"""
        customer_obj = models.Customer.objects.filter(pk=n).first()
        # 通过modelform实例化,传递页面提交的post数据,指定instance实例
        form_obj = formAuth.CustomerAddMF(request.POST, instance=customer_obj)
        if form_obj.is_valid():
            form_obj.save()  # 合法后保存,注意如果实例化时,没有传实例,是创建记录,指定了实例才是修改数据
            return redirect("common")

        else:
            # 数据不合法,保留页面和原始数据,并给出错误提示
            return render(request, "common_add.html", {"form_obj": form_obj})

编辑客户视图
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

修改客户记录html文件

modelform组件有一个功能,就是在实例化的时候,指定instance的对象,可以直接获取对象的值,并在页面中渲染出来,不需要我们再通过render单独传递数据渲染了。所以我们修改数据的页面的html文件与添加的页面没有差别,这里就直接使用上面common_add.html文件即可。

其次,在post请求提交数据后,modelform实例化对象的时候,如果直接传递request.post数据,通过modelform对象.save方法可以新建数据;如果指定了instance为哪个记录对象,save方法就是修改这个记录对象的数据。

6.删除客户的视图和模板

删除客户数据视图

# 删除公共客户记录
class CommonDel(views.View):
    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        res = super().dispatch(request, *args, **kwargs)
        return res

    def get(self, request, n):
        # 根据前端传递的客户id,查找客户对象
        customer_obj = models.Customer.objects.filter(pk=n)
        customer_obj.delete()  # fixme 对象的delete方法删除,其实实际工作中不应是真的删除,而是修改该记录的删除状态为True,即可。
        return redirect("common_list")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

删除数据不需要页面展示,其实我们本应该在删除前有一个确认过程,而不是点击一下,就直接删除,这样可能会导致误删。至于确认删除的过程,我们可通过js代码来实现,这里我就不详细写了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/71767
推荐阅读
相关标签
  

闽ICP备14008679号