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

本文介绍了一个Django实战项目中的客户管理模块,包括客户数据的增删改查功能实现。详细讲解了公共客户数据的URL配置、视图函数、模板设计,以及添加、编辑和删除客户视图的编写。同时提到了模板继承和ModelForm在数据处理中的应用。
摘要由CSDN通过智能技术生成

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

1.业务回顾

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

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

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

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

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

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

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

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"),
]

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

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

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

  • 在客户数据展示的视图中我们使用了django自带的auth认证装饰器,装饰器在验证失败后会跳转login页面,但是django默认配置的跳转login页面url并不是我们想要的,需要我们在settings中配置一下。
# 配置登录认证失败跳转的页面
LOGIN_URL = '/crmweb/login/'
  • 在数据展示页面中,还使用了自定义分页,自定义分页博客中有,就不详述了,想要查看点这里: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>

  • 批量操作功能

批量操作功能的实现,也是通过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  # 返回已经被选择的用户

公户展示及批量操作视图
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 -->
            <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值