1.展示记录页面创建
(1)crm/urls.py中:
# 展示跟进记录
url(r'consult_record_list/', views.ConsultRecord.as_view(), name='consult_record'),#我用CBV(用类写View)方式写.
(2)views.py中:
#展示跟进记录 class ConsultRecord(View): def get(self, request):#定义get方法 all_consult_record = models.ConsultRecord.objects.filter(delete_status=False) return render(request, 'crm/consult_record_list.html',{'all_consult_record':all_consult_record})#传给模版
(3)templates/crm/consult_record_list.html中:
{% extends 'layout.html' %} {% block css %} {% endblock %} {% block content %}{% endblock %}Panel heading
效果如下:
2.添加跟进记录页面创建:
(1)urls.py中:
# 添加跟进记录 url(r'consult_record/add/', views.add_consult_record, name='add_consult_record '),
(2)views.py中:使用下步中from表单:
from crm.forms import CustomerForm,ConsultRecordForm#导入form # 添加跟进记录 def add_consult_record(request): form_obj = ConsultRecordForm()#生成一个空的form对象 return render(request, 'crm/add_consult_record.html',{'form_obj':form_obj})
(3)我现在要通过form表单才能提交数据,forms.py中:
from django import forms from crm import models #导入crm下的数据库 from django.core.exceptions import ValidationError#导入报错方法 class BaseForm(forms.ModelForm):#定义一个基类 def __init__(self, *args, **kwargs): # 初始化--用来给多个插件做css样式 super().__init__(*args, **kwargs) # 继承父类的初始法 for filed in self.fields.values(): # 给每一个插件 filed.widget.attrs.update({'class': 'form-control'}) # update是更新attrs插件字典的css样式 # 注册form class RegForm(BaseForm): password = forms.CharField( #给前端增加密码字段并展示 label='密码', widget=forms.widgets.PasswordInput(), #给密码框做隐形输入 min_length=6, error_messages={'min_length': '最小长度为6'} #配置字段的错误提示 ) re_password = forms.CharField(#给前端增加确认密码字段展示并隐形输入 label='确认密码', widget=forms.widgets.PasswordInput() ) class Meta:#这个类是为专字段做配置用 model = models.UserProfile #根据哪个表的models生成对应字段 fields = ['username', 'password', 're_password', 'name', 'department'] # 在前端显示哪些指定字段 # exclude = [''] widgets = {#为多个字段做隐形输入 ----用加插件widgets 'username': forms.widgets.EmailInput(attrs={'class': 'form-control'}), #用插件attrs给username的input做css样式 'password': forms.widgets.PasswordInput, } labels = {#让多个字段中文显示---用加插件labels 'username': '用户名', 'password': '密码', 'name': '姓名', 'department': '部门', } error_messages = { #配置字段的错误提示 'password': { 'required': '密码不能为空', } } def clean(self):#全局勾子---密码校验 pwd = self.cleaned_data.get('password') re_pwd = self.cleaned_data.get('re_password') if pwd == re_pwd: return self.cleaned_data self.add_error('re_password', '两次密码不一致')#错误则添加到 raise ValidationError('两次密码不一致')#报错 # 客户form class CustomerForm(BaseForm): class Meta:#做配置用 model = models.Customer fields = '__all__' #要显示的字段 widgets = { #此插件作用是把course课程字段改成多选框 'course': forms.widgets.SelectMultiple } # 跟进记录form class ConsultRecordForm(BaseForm): class Meta: model = models.ConsultRecord exclude = ['delete_status']
(4)templates/crm/add_consult_record.html中:
{% extends 'layout.html' %} {% block content %}添加跟进记录{% endblock %}(5)consult_record_list.html:
{% extends 'layout.html' %} {% block css %} {% endblock %} {% block content %}{% endblock %}Panel heading效果如下:
但是如下图中:出现的是对象所以要用__str__方法转换。
(6)models.py的Customer表中定义__str__方法:
def __str__(self): return "{}<{}>".format(self.name, self.qq)#拼接
(7)开始提交添加跟进记录页面的数据
即post请求,
views.py中:
# 添加跟进记录 def add_consult_record(request): form_obj = ConsultRecordForm()#生成一个空的form对象 if request.method == 'POST': form_obj = ConsultRecordForm(request.POST)#添加到form对象中数据 if form_obj.is_valid():#校验成功 form_obj.save()#保存 return redirect(reverse('consult_record'))#跳转到展示跟进记录页面(consult_recordj是别名) return render(request, 'crm/add_consult_record.html',{'form_obj':form_obj})#如果form对象是空的则在添加跟记录页面如下图中点击提交按钮后
效果如下:
3.跟进记录的编辑页面创建
(1)urls.py中:
# 编辑跟进记录
url(r'consult_record/edit/(\d+)/', views.edit_consult_record, name='edit_consult_record'),(2)views.py中:
# 编辑跟进记录 def edit_consult_record(request, edit_id): obj = models.ConsultRecord.objects.filter(id=edit_id).first()#返回queryset中匹配到的第一个对象 form_obj = ConsultRecordForm(instance=obj)#将对象与form对象关联起来 if request.method == 'POST': form_obj = ConsultRecordForm(request.POST, instance=obj)#添加到form对象中数据 if form_obj.is_valid(): form_obj.save() return redirect(reverse('consult_record')) return render(request, 'crm/edit_consult_record.html', {'form_obj': form_obj})(3)templates/crm/edit_consult_record.html(复制一份add_consult_record.html并修改)中:
<div class="panel-heading">编辑跟进记录div>(4)consult_record_list.html跟进记录展示页面中:
{% extends 'layout.html' %} {% block css %} {% endblock %} {% block content %}{% endblock %}Panel heading
效果如下图中:点击编辑按钮即可进入编辑页面:
这样展示和添加跟进记录就做完了。
4.展示我的跟进记录
(1)layout.html中:添加如下代码
效果如下:
但这些跟进记录是所有的(如下图中),而不是当前销售的客户跟进记录,我应该只让它显示当前销售自己的:
上述这些客户是form自动给它生成的.--所以我对它的choices属性修改即可----所咨询的字段(models.py中是跟进记录表的customer字段)。
(2)forms.py中:
# 跟进记录form class ConsultRecordForm(BaseForm): class Meta: model = models.ConsultRecord exclude = ['delete_status'] def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) self.fields['customer'].widget.choices = ((1,'xxxx'),)效果如下:
(3)但我这个是写死的,所咨询客户应该给我的是当前用户/销售的所有客户。
所以要先拿到用户request.user---而这个user就让它从views.py中传过来
# 跟进记录form class ConsultRecordForm(BaseForm): class Meta: model = models.ConsultRecord exclude = ['delete_status'] def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs)#self.instance.consultant.customers.all()是拿到当前用户的所有客户 #i就是一个客户,我把它组装成元组(id,名字)传到所咨询客户customer字段的choices中 self.fields['customer'].widget.choices = [ (i.id, i) for i in self.instance.consultant.customers.all() ](4)views.py中:
# 添加跟进记录 def add_consult_record(request): # 注意models.CourseRecord()它是一个类对象(表),下行是我对它实例化并传参---即我自己给它封装数据--那它就只在内存中---等于object.create方法创建对象 obj = models.ConsultRecord(consultant=request.user)#CourseRecord表中的consultant跟进人字段我给它传参为当前用户--即我对它做了封装 #obj.save()#把我封装的数据保存到数据库中才能取 form_obj = ConsultRecordForm(instance=obj)#通过instance把跟进人对象和form表单关联起来---forms.py中通过instance.consultant即可拿到跟进人即当前用户 if request.method == 'POST': form_obj = ConsultRecordForm(request.POST)#添加到form对象中数据 if form_obj.is_valid():#校验成功 form_obj.save()#保存 return redirect(reverse('consult_record'))#跳转到展示跟进记录页面(consult_recordj是别名) return render(request, 'crm/add_consult_record.html',{'form_obj':form_obj})#如果form对象是空的则在添加跟记录页面效果如下:拿到当前用户的所有客户了---这样就可以了
(5)限制跟进人是当前的用户(销售)---同样的跟进记录的编辑因为它也走__init__
跟进记录表ConsultRecord表中的consultant跟进人字段并在forms.py中写跟进人插件并让它的choice属性就行了,如下就行了
# 跟进记录form class ConsultRecordForm(BaseForm): class Meta: model = models.ConsultRecord exclude = ['delete_status'] def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs)#self.instance.consultant.customers.all()是拿到当前用户的所有客户 customer_choice =[(i.id, i) for i in self.instance.consultant.customers.all()] # 限制客户是当前销售的私户-- self.fields['customer'].widget.choices = customer_choice # 限制跟进人是当前的用户(销售) self.fields['consultant'].widget.choices = [(self.instance.consultant.id, self.instance.consultant), ](6)views.py中把添加跟进记录和编辑跟进记录整合成一个views:
先让它们url走一个视图--->urls.py中:
from django.conf.urls import url, include from crm import views urlpatterns = [ # 公户 url(r'customer_list/', views.CustomerList.as_view(), name='customer'), # 私户 url(r'my_customer/', views.CustomerList.as_view(), name='my_customer'), # 增加客户 url(r'customer/add/', views.customer, name='add_customer'), # 编辑客户 url(r'customer/edit/(\d+)', views.customer, name='edit_customer'), # 展示跟进记录 url(r'consult_record_list/', views.ConsultRecord.as_view(), name='consult_record'), # 我用CBV(用类写View)方式写. # 添加跟进记录 url(r'consult_record/add/', views.consult_record, name='add_consult_record'), # 编辑跟进记录 url(r'consult_record/edit/(\d+)/', views.consult_record, name='edit_consult_record'), ]再views.py中:
from django.shortcuts import render, redirect, reverse, HttpResponse from django.contrib import auth from crm.forms import RegForm from crm.forms import RegForm, CustomerForm, ConsultRecordForm from crm import models from django.utils.safestring import mark_safe from utils.pagination import Pagination from django.views import View from django.db.models import Q from django.http import QueryDict import copy def login(request): err_msg = '' if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') obj = auth.authenticate(request, username=username, password=password) if obj: auth.login(request, obj) return redirect(reverse('my_customer')) err_msg = '用户名或密码错误' return render(request, 'login.html', {'err_msg': err_msg}) # 注册 def reg(request): form_obj = RegForm() if request.method == 'POST': form_obj = RegForm(request.POST) if form_obj.is_valid(): # 创建新用户 # 方法一 # form_obj.cleaned_data.pop('re_password') # models.UserProfile.objects.create_user(**form_obj.cleaned_data) # 方法二 obj = form_obj.save() obj.set_password(obj.password) obj.save() return redirect('/login/') return render(request, 'reg.html', {'form_obj': form_obj}) # 展示客户列表 def customer_list(request): query = request.GET.get('query') if request.path_info == reverse('customer'): all_customer = models.Customer.objects.filter(Q(qq__contains=query)|Q(name_contains=query),consultant__isnull=True) else: all_customer = models.Customer.objects.filter(Q(qq__contains=query)|Q(name_contains=query),consultant=request.user) page = Pagination(request, all_customer.count()) return render(request, 'crm/customer_list.html', {"all_customer": all_customer[page.start:page.end], 'pagination': page.show_li}) # 展示客户列表CBV class CustomerList(View): def get(self, request): q = self.get_search_contion(['qq','name']) if request.path_info == reverse('customer'): all_customer = models.Customer.objects.filter(q,consultant__isnull=True) else: all_customer = models.Customer.objects.filter(q,consultant=request.user) query_params = copy.deepcopy(request.GET) page = Pagination(request, all_customer.count(),query_params,2) add_btn,query_params = self.get_add_btn()# 接收查询的条件 return render(request, 'crm/customer_list.html', {"all_customer": all_customer[page.start:page.end], 'pagination': page.show_li, 'add_btn': add_btn, 'query_params': query_params})#把这个条件也传给模版 def post(self, request): # 定义post请求 # 处理post提交的action的动作,处理完后让它返回上面的get这个方法再做一遍,相当于redirect跳转只不过不让用户再发一次请求了,一次性处理完 action = request.POST.get('action') # 拿到具体要操作的动作(如删除或放入私户这个动作) if not hasattr(self, action): # 判断若没有action这个动作就不让你再往下执行 return HttpResponse('非法操作') ret = getattr(self, action)() # 获取action 这个就是自己定义的下面的action方法,加()是执行此方法 if ret: return ret return self.get(request) # 返回上面的get这个方法 def multi_apply(self): # action的方法 # 公户变私户方法 ids = self.request.POST.getlist('id') # 拿到客户Id # models.Customer.objects.filter(id__in=ids)这个拿到的就是你当前的传过来的多个客户,前面加*号是把它打散 # self.request.user.customers拿到的是models.py中的一对多的管理对象 self.request.user.customers.add(*models.Customer.objects.filter(id__in=ids)) def multi_pub(self): # action的方法 # 私户变公户方法 ids = self.request.POST.getlist('id') self.request.user.customers.remove(*models.Customer.objects.filter(id__in=ids)) def get_search_contion(self,query_list): query = self.request.GET.get('query', '') q = Q() q.connector = 'OR' for i in query_list: q.children.append(Q(('{}__contains'.format(i), query))) return q def get_add_btn(self):#做的就是跳转到它自己生成的a标签中的url中 # 获取添加按钮 url = self.request.get_full_path()#获取当前页面的url qd = QueryDict()#生成网址字典对象QueryDict qd._mutable = True#设置成可对字典对象修改格式 qd['next'] = url#qd字典中加next键和值当前页面的url query_params = qd.urlencode()#做转换将网址字典转成query=6的格式 # 做拼接生成a标签:add_customer是urls.py中的customer/add/的别名 add_btn = '添加'.format(reverse('add_customer'), query_params) return mark_safe(add_btn),query_params#把查询的条件返回 # 新增和编辑客户 def customer(request, edit_id=None):#一个url传参数一个不传,那这个时候就用默认值edit_id=None即没有参数就是空的,有就传 obj = models.Customer.objects.filter(id=edit_id).first() form_obj = CustomerForm(instance=obj) if request.method == 'POST': form_obj = CustomerForm(request.POST, instance=obj) if form_obj.is_valid(): form_obj.save() # 获取到next next = request.GET.get('next') if next: return redirect(next) return redirect(reverse('customer')) return render(request, 'crm/customer.html', {"form_obj": form_obj, "edit_id": edit_id}) #展示跟进记录 class ConsultRecord(View): def get(self, request):#定义get方法 all_consult_record = models.ConsultRecord.objects.filter(delete_status=False) return render(request, 'crm/consult_record_list.html',{'all_consult_record':all_consult_record})#传给模版 # 新增和编辑跟进记录 def consult_record(request, edit_id=None): obj = models.ConsultRecord.objects.filter(id=edit_id).first() or models.ConsultRecord(consultant=request.user) form_obj = ConsultRecordForm(instance=obj) if request.method == 'POST': form_obj = ConsultRecordForm(request.POST, instance=obj) if form_obj.is_valid(): form_obj.save() return redirect(reverse('consult_record', args=(0,))) return render(request, 'crm/edit_consult_record.html', {'form_obj': form_obj}) # 测试分页 # 测试数据 users = [{'name': 'alex{}'.format(i), 'pwd': 'alexdsb{}'.format(i)} for i in range(1, 302)] def user_list(request): page = Pagination(request, len(users)) return render(request, 'user_list.html', { "data": users[page.start:page.end], # 'total_num': range(page_start, page_end + 1) 'html_str': page.show_li })5.跟进页面流程梳理:
1.展示某个客户的跟进记录:
(1)urls.py中:做限制 ---如果你要的是某个客户记录的id,那展示的就是这个客户的所有跟进记录--如果你输入0的话,就是所有人的跟进记录
# 展示跟进记录 url(r'consult_record_list/(\d+)', views.ConsultRecord.as_view(), name='consult_record'),(2)views.py中:
# 展示跟进记录 class ConsultRecord(View): def get(self, request,customer_id):#customer_id是models.py中的跟进记录表的customer字段的外键
if customer_id == '0':#当前销售只能看他自己的客户跟进记录 all_consult_record = models.ConsultRecord.objects.filter(delete_status=False,consultant=request.user) else: all_consult_record = models.ConsultRecord.objects.filter(customer_id=customer_id,delete_status=False) return render(request, 'crm/consult_record_list.html', { 'all_consult_record': all_consult_record })(3)此时我左侧的我的跟进记录页面的地址也得修改:layout.html中:
{% load static %} "en"> "UTF-8"> "stylesheet" href="{% static 'plugins/bootstrap-3.3.7/css/bootstrap.css' %}">{# 导入bootstrap样式 #} "stylesheet" href="{% static 'css/layout.css' %}"> "icon" href="{% static 'imgs/layout/luffy-logo.png' %}"> "stylesheet" href="{% static 'plugins/font-awesome-4.7.0/css/font-awesome.css' %}">CRM管理系统 {% block css %} {% endblock %}class="container-fluid">{% block js %} {% endblock %}class="row">class="col-sm-3 col-md-2 sidebar">class="nav nav-sidebar">
- "{% url 'customer' %}">客户列表
- "{% url 'my_customer' %}">我的客户
- 我的跟进记录
- "#">Reports
- "#">Analytics
- "#">Export
class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> {% block content %} {% endblock %}效果如下:
(4)在我的客户页面客户后面还应该有一个按钮,一点击它就能看到该客户的跟进记录:customer_list.html中:
{% extends 'layout.html' %} {% block css %} {% endblock %} {% block content %}class="panel panel-default">{% endblock %}class="panel-heading">Panel headingclass="panel-body"> "{% url 'add_customer' %}?{{ query_params }}" class="btn btn-primary btn-sm">添加"text-align: center">效果如下:我的客户页面点某客户的查看跟进就能进入该客户的详细跟进页面中了
(5)此时注意因为你urls.py中url地址变了加了参数id,所以你views.py中也得变:
# 展示跟进记录
url(r'consult_record_list/(\d+)', views.ConsultRecord.as_view(), name='consult_record'),views.py中:也应该再加参数
# 新增和编辑跟进记录 def consult_record(request, edit_id=None): obj = models.ConsultRecord.objects.filter(id=edit_id).first() or models.ConsultRecord(consultant=request.user) form_obj = ConsultRecordForm(instance=obj) if request.method == 'POST': form_obj = ConsultRecordForm(request.POST, instance=obj) if form_obj.is_valid(): form_obj.save() return redirect(reverse('consult_record', args=(0,))) return render(request, 'crm/edit_consult_record.html', {'form_obj': form_obj})
(7)