饮冰三年-人工智能-Python-34CRM项目实战

 Customer Relationship Management。客户管理系统。

源码位置:https://github.com/1692134188/AaronCRM.git

 创建项目、实体类,设置登录页面这些等不再一一介绍。着重介绍一下内容

一、模仿Django Admin创建的KingAdmin

 

 我们这次以QA的模式整理思路

Q1:我们要达到的效果是什么样的?

  A1:

 

 Q2:整体实现思路?

  A2:1:每个模块下建立相应kingadmin.py文件。ps:其作用是将需要管理的表注册进来,同时可以配置一些自定制设置(展示、过滤、查询)等

     2:程序启动==>自动将所有模块下kingadmin中的信息存放到一个全局变量中,其全局变量的格式如下:

    enabled_admin={'模块名1':{'表名1':相应配置,'表名2':相应配置},'模块名2':{'表名1':相应配置}}

    enabled_admin={'crm':{'Customer':CustomerAdmin,'role':RoleAdmin},...}

Q3:对于A2中的自动注册如何实现?

  A3:1:在KingAdmin模块下创建app_setup.py文件。    

# Q1:该文件的作用是什么?
#     A1:查找当前项目中setting文件中配置的模板。
#         获取每个模块下的kingadmin中的注册信息
#         将注册信息写入到全局变量中

# Q2:如何动态获取配置文件中的内容
#     A2:导入conf文件,conf.settings.INSTALLED_APPS

# Q3:如何将每个模块下的信息注册到全局变量中
#     A3:通过sites.py 方法

from django import conf

def kingadmin_auto_discover():
    mods=conf.settings.INSTALLED_APPS
    for app_name in mods:
        try:
            mod = __import__('%s.kingadmin' % app_name) #动态加载类和函数
        except ImportError:
            pass
app_setup.py

     2:创建site文件并调用

# Q1:该文件的作用是什么?
#   A1:将每个模块下的信息注册到全局变量中

class AdminSite(object):
    def __init__(self):
        self.enabled_admins={}

    def register(self,model_class,admin_class=None):
        app_name=model_class._meta.app_label #获取模块名称
        model_name = model_class._meta.model_name #获取表名称
        if app_name not in self.enabled_admins:
            self.enabled_admins[app_name]={}
        self.enabled_admins[app_name][model_name]=admin_class

site=AdminSite()
site.py

    3:每个模块下创建相应的kingadmin.py文件

from KingAdmin import sites
from KingAdmin.sites import site
from CRM import models

# Register your models here.
print('crm kingadmin ............')
class CustomerAdmin(sites.AdminSite):
    list_display = ['name','source','contact_type','contact','consultant','consult_content','status','date']
    list_filter = ['source','consultant','status','date']
    search_fields = ['contact','consultant__name']

site.register(models.CustomerInfo,CustomerAdmin)
site.register(models.CustomerFollowUp)
site.register(models.ClassList)
site.register(models.Course)
site.register(models.Role)
site.register(models.Menus)
site.register(models.CourseRecord)
site.register(models.StudyRecord)
site.register(models.Student)
site.register(models.UserProfile)
CRM模块下的kingadmin.py

    同样的添加一个Student模块,其中有Test类

    4:KingAdmin中在View中进行的调用

from django.shortcuts import render,redirect
from django.contrib.auth import login,authenticate,logout
from KingAdmin import app_setup
from KingAdmin.sites import site
app_setup.kingadmin_auto_discover()

def app_index(request):
    return render(request, 'kingadmin/app_index.html', {'site': site})
# Create your views here.
def acc_login(request):
    error_msg=""
    if request.method=="POST":
        username=request.POST.get('username')
        password= request.POST.get('password')

        user=authenticate(username=username,password=password)
        if user:
            login(request,user)
            return redirect(request.GET.get('next', '/kingadmin/'))
        else:
            error_msg = "Wrong username or password!"
    return render(request,"kingadmin/login.html", {'error_msg':error_msg})

def acc_logout(request):
    logout(request)
    return redirect("/kingadmin/login/")
views
{% extends 'kingadmin/index.html' %}
{% block  right-content-container %}
    <h2 class="page-header">app</h2>

    <div>
        {% for app_name,app_tables  in site.enabled_admins.items %}
            <table class="table table-striped">
                <thead>
                <tr>
                    <th>{{ app_name }}</th>
                </tr>
                </thead>
                <tbody>
                {% for model_name in app_tables %}
                    <tr>
                        <td>{{ model_name }}</td>
                        <td>ADD</td>
                        <td>Change</td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        {% endfor %}

    </div>

{% endblock %}
app_index.html

此时效果是:

 Q4:如何为表名添加url链接?

  A4:在sites文件中注册方法register的时候,把model_class赋值给admin_class属性。前端页面通过该属性值获取到对应的url。

    ps:需要注意的是,通过定义一个基类BaseKingAdmin,来解决某些注册类中没有admin_class属性的问题   

      需要注意的是,为了避免多个model共享同一个BaseKingAdmin内存对象,需要将其实例化

Q5:如何展示页面?

  A5:拿到要该的类,通过自定义模板反射出其要展示的内容。 ps:需要注意枚举类型要转换成相应的汉字

from django.template import Library
from django.utils.safestring import mark_safe 
register = Library() 

@register.simple_tag
def build_table_row(obj, admin_class):
    # Q1:该方法的作用是什么?
    # A1:通过模板,将表中的记录生成相应的html元素
    ele = ""
    for column_name in admin_class.list_display:
        column_obj = admin_class.model._meta.get_field(column_name)
        if column_obj.choices:
            # 如果是枚举类型,需要将其转换成相应的汉字
            column_date = getattr(obj,'get_%s_display' %column_name)()
        else:
            column_date = getattr(obj, column_name)
        td_ele = "<td>%s</td>" % column_date
        ele += td_ele
    return mark_safe(ele)
自定义模板页面

 Q6:搜索功能

  A6:通过request.GET方法,从url拿到查询条件,过滤查询即可。ps:需要注意日期类型。  

from django.template import Library
from django.utils.safestring import mark_safe
import datetime,time
register = Library()


@register.simple_tag
def build_filter_ele(filter_column,admin_class):

    column_obj = admin_class.model._meta.get_field(filter_column)
    print("column obj:",column_obj)
    try:
        filter_ele = "<select name='%s'>" % filter_column
        for choice in column_obj.get_choices():
            selected = ''
            if filter_column in admin_class.filter_condtions:#当前字段被过滤了
                # print("filter_column", choice,
                #       type(admin_class.filter_condtions.get(filter_column)),
                #       admin_class.filter_condtions.get(filter_column))
                if str(choice[0]) == admin_class.filter_condtions.get(filter_column):#当前值被选中了
                    selected = 'selected'
                    print('selected......')

            option = "<option value='%s' %s>%s</option>" % (choice[0],selected,choice[1])
            filter_ele += option
    except AttributeError as e:
        print("err",e)
        filter_ele = "<select name='%s__gte'>" % filter_column
        if column_obj.get_internal_type() in ('DateField','DateTimeField'):
            time_obj = datetime.datetime.now()
            time_list = [
                ['','------'],
                [time_obj,'Today'],
                [time_obj - datetime.timedelta(7),'七天内'],
                [time_obj.replace(day=1),'本月'],
                [time_obj - datetime.timedelta(90),'三个月内'],
                [time_obj.replace(month=1,day=1),'YearToDay(YTD)'],
                ['','ALL'],
            ]

            for i in time_list:
                selected = ''
                time_to_str = ''if not i[0] else  "%s-%s-%s"%(i[0].year,i[0].month,i[0].day)
                if  "%s__gte"% filter_column in admin_class.filter_condtions:  # 当前字段被过滤了
                    print('-------------gte')
                    if time_to_str == admin_class.filter_condtions.get("%s__gte"% filter_column):  # 当前值被选中了
                        selected = 'selected'
                option = "<option value='%s' %s>%s</option>" % 
                         (time_to_str ,selected,i[1])
                filter_ele += option

    filter_ele += "</select>"
    return mark_safe(filter_ele)


@register.simple_tag
def build_table_row(obj, admin_class):
    # Q1:该方法的作用是什么?
    # A1:通过模板,将表中的记录生成相应的html元素
    ele = ""
    for column_name in admin_class.list_display:
        column_obj = admin_class.model._meta.get_field(column_name)
        if column_obj.choices:
            # 如果是枚举类型,需要将其转换成相应的汉字
            column_date = getattr(obj, 'get_%s_display' % column_name)()
        else:
            column_date = getattr(obj, column_name)
        td_ele = "<td>%s</td>" % column_date
        ele += td_ele
    return mark_safe(ele)
kingadmin_tags.py

Q7:分页功能

  A7:可以参考https://docs.djangoproject.com/en/2.2/topics/pagination/。文档中相应的功能介绍

Q8:如何实现排序

  A8:给相应的标题上添加链接,通过地址栏传值到后台。后台取到相应的值,进行判断

    ps:需要注意细节点:1:升序降序问题。2:排序上下箭头展示  3:排序和查询的问题(隐藏域)   4:排序和分页的问题 

Q9:如何实现关键字段搜索功能

  A9:添加检索文本域字段,注意搜索关键字段和过滤条件的状态保持

Q10:如何实现任意表的增删改查?

  A10:首先要实现对任意表的操作,name需要通过动态生成的方式动态生成modelform。

    1:在KingAdmin创建form_handle,以动态生成modelform    

from django.forms import ModelForm


def create_dynamic_model_form(admin_class,form_add=False):
    """动态的生成modelform
    form_add: False 默认是修改的表单,True时为添加
    """

    class Meta:
        model = admin_class.model
        # fields = ['name','consultant','status']
        fields = "__all__"
        if not form_add:#change
            exclude = admin_class.readonly_fields
            admin_class.form_add = False #这是因为自始至终admin_class实例都是同一个,
            # 这里修改属性为True是为了避免上一次添加调用将其改为了True
        else: #add
            admin_class.form_add = True

    def __new__(cls, *args, **kwargs):
        print("__new__",cls,args,kwargs)
        for field_name in cls.base_fields:
            filed_obj = cls.base_fields[field_name]
            filed_obj.widget.attrs.update({'class':'form-control'})
            # if field_name in admin_class.readonly_fields:
            #     filed_obj.widget.attrs.update({'disabled': 'true'})
            #     print("--new meta:",cls.Meta)

        #print(cls.Meta.exclude)
        return  ModelForm.__new__(cls)

    dynamic_form = type("DynamicModelForm" ,(ModelForm,) ,{'Meta' :Meta,'__new__':__new__})

    print(dynamic_form)
    return dynamic_form
form_hander

 Q11:如何实现表的修改操作?

  A11:展示页面的时候将数据显示出来,添加保存按钮,通过post方法后台保存即可

Q12:如何完成新增操作?

  A12:新增操作同样不是很复杂,

    ps:1和编辑可以共用模板页面。2:某些只读字段 例如状态等,一旦输入不可随意修改。通过在kingadmin.py中配置readonly_fields属性

Q13:对many2many的多选字段进行完善。

  A13:可实现多选,模糊查询等功能

 Q14:删除功能的实现。

  A14:删除时给出提示所关联的表提示

Q15:如何实现action

  A15:通过在kingadmin.py中配置action属性并定义配套的方法,View中反射实现自定义方法,进行操作

Q16:如何实现默认的自定义删除action

  A16:注意首先model类中相应的属性需要设置成可以级联删除 如: referral_from = models.ForeignKey("self", blank=True, null=True, verbose_name="转介绍",on_delete=models.CASCADE)

  然后在admin_base.py和view.py文件中做判断

Q17:面包屑

  A17:在需要添加的页面修改即可

 二、CRM项目学员报名流程

Q1:学员报名的大致步骤有哪些?

  A1:选择班级(销售人员)==> 学生上传个人信息  ==> 缴费 ==>

Q2:需要哪些准备工作?

  A2:1:基础数据的维护(创建Menu链接、为角色分配菜单)

    2:维护模型:

          a:客户信息表(CustomerInfo)添加一些身份证号、性别、紧急联系人等个人信息

          b:新增 合同模板表 (ContractTemplate),该表和班级表相关联

          c:新增 学员报名表(StudentEnrollment)

          d:新增 学员缴费记录表(PaymentRecord)

Q3:销售人员为学院分配班级?

  A3:班级分配完成后,会生成相应的链接,学生拿到链接地址后,学生上传个人信息。

Q4:学生填写个人信息有哪些亮点?

  A4:1:利用了djangoform验证,并且设置可可读属性也不能修改。

     2:附件上传DropZone控件

Q5:DropZone附件上传具体的步骤有哪些?

  A5:1:引入相应的js和css

     2:html页面中添加相应的<form>表单,并设置action提交路径

    `3:后台代码处理,setting中配置相应的文件路径 并且再相应的目录下创建文件夹

原文地址:https://www.cnblogs.com/YK2012/p/11773010.html