crm项目04--添加,编辑客户,公户和私户的展示,公户和私户的转化
这篇博客主要用来实现这样的效果

templateresponse
本文实现功能(共4个)
-
添加客户
-
编辑客户
-
公户和私户的展示,公户就是所有用户都可以看到的客户,私户就是用户自己的客户
-
公户和私户的转化
实现需求的整体思路
1.添加客户
添加客户用django的form组件来对前端进行渲染, 设立一个前端模版,从后端传递一个查询出的queryset对象,通过render({“form_obj”:form_obj})的方式传到html页面,在页面中使用for进行遍历进而显示所需要添加的图片
要点
- 视图函数特别多,可以建立一个views文件夹 ,里面存放对不同对象操作的views.py,原有的单个views.py文件就不需要了,删掉即可,或者迁移到views文件夹下面

-
前端直接遍历传过去的form_obj对象即可,使用for循环生成表单
View Code{% extends 'layout.html' %} {% block content %} <div class="panel panel-default"> <div class="panel-heading">添加</div> <div class="panel-body"> <form class="form-horizontal" novalidate method="post" action="{% url 'customer_add' %}"> {% csrf_token %} {% for customer in form_obj %} <div class="form-group {% if customer.errors.0 %}has-error{% else %}{% endif %}"> <label for="{{ customer.id_for_label }}" class="col-sm-2 control-label">{{ customer.label }}</label> <div class="col-sm-10"> {{ customer }} <span></span> </div> </div> {% endfor %} <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">保存</button> </div> </div> </form> </div> </div> {% endblock %} -
在form表单中,为了保证页面的样式同一,每个自定义form都一个个添加样式非常繁琐,可以将使用到的提出来,变成一个父类,让其他的类继承它.
View Codefrom django import forms from app01 import models import hashlib from django.core.exceptions import ValidationError # 定义Boostrap表单样式的类 class BootstrapForm(forms.ModelForm): def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) for field in self.fields.values(): field.widget.attrs.update({'class':'form-control'}) # 注册表单 class RegForm(BootstrapForm): password = forms.CharField(widget=forms.PasswordInput,label='密码',min_length=3) re_password = forms.CharField(widget=forms.PasswordInput,label='确认密码',min_length=3) class Meta: model = models.UserProfile fields = "__all__" exclude = ['is_active'] labels = { 'username':'用户名', } # widgets = { # "password": forms.widgets.PasswordInput(attrs={"class":"form-control"}) # } def __init__(self, *args, **kwargs): super().__init__(*args,**kwargs) print(self.fields) for field in self.fields.values(): field.widget.attrs.update({'class':'form-control'}) def clean(self): print(self.cleaned_data) pwd = self.cleaned_data.get('password','') re_pwd = self.cleaned_data.get('re_password','') if pwd == re_pwd: # md5验证 s = hashlib.md5() s.update(pwd.encode('utf-8')) ret = s.hexdigest() self.cleaned_data['password'] = ret return self.cleaned_data else: self.add_error('re_password','两次密码输入不一致') raise ValidationError('两次密码输入不一致') # Customer添加表单 class CustomerForm(BootstrapForm): class Meta: model = models.Customer fields = "__all__" def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) self.fields["course"].widget.attrs.pop('class')
-
在样式框中,想让输入框报错显示一个红色框体,可以这样写,这样

-
<div class="form-group {% if customer.errors.0 %}has-error{% else %}{% endif %}">
2.编辑客户
编辑客户同样使用到form组件,需要注意的是django的form组件已经为我们提供了将值直接传给表单的功能,
要点
-
使用form组件的表单功能,form_obj = CustomerForm(instance=obj)直接可以生成包含有原始数据的编辑表单.
View Code# 编辑客户 def customer_edit(request, edit_id): obj = models.Customer.objects.filter(pk=edit_id).first() # 处理POST if request.method == "POST": # 包含提交的数据 原始数据 form_obj = CustomerForm(request.POST,instance=obj) if form_obj.is_valid(): form_obj.save() return redirect(reverse('customer_list')) else: # 包含原始数据的form表单 form_obj = CustomerForm(instance=obj) return render(request, 'customer_edit.html', {"form_obj": form_obj})
-
编辑客户和添加客户功能重复,视图函数可以合并成为一个,前端页面也可以合成一个,不过在前端页面中,显示页头 编辑/添加 时可以在后端判断完成后传递给前端 title = '编辑' if edit_id else '添加' 即可
View Code{% extends 'layout.html' %} {% block content %} <div class="panel panel-default"> <div class="panel-heading">{{ title }}</div> <div class="panel-body"> <form class="form-horizontal" novalidate method="post"> {% csrf_token %} {% for customer in form_obj %} <div class="form-group {% if customer.errors.0 %}has-error{% else %}{% endif %}"> <label for="{{ customer.id_for_label }}" class="col-sm-2 control-label">{{ customer.label }}</label> <div class="col-sm-10"> {{ customer }} <span></span> </div> </div> {% endfor %} <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">保存</button> </div> </div> </form> </div> </div> {% endblock %}简化代码后的change功能
def customer_change(request, edit_id=None): obj = models.Customer.objects.filter(pk=edit_id).first() # 处理POST if request.method == 'POST': # 包含提交的数据 原始数据 form_obj = CustomerForm(request.POST, instance=obj) if form_obj.is_valid(): form_obj.save() # 跳转到展示页面 return redirect(reverse('customer_list')) else: form_obj = CustomerForm(instance=obj) title = '编辑客户' if edit_id else '添加客户' obj = HttpResponse('xxx') return render(request, 'customer_change.html', {'title': title, 'form_obj': form_obj})
简化后的前端页面
{% extends 'layout.html' %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">{{ title }}</h4>
</div>
<div class="panel-body">
<div class="col-lg-8 col-lg-offset-2 " style="margin-top: 10px">
<form class="form-horizontal" novalidate method="post">
{% csrf_token %}
{% for field in form_obj %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
<label for="{{ field.id_for_label }}"
class="col-sm-2 control-label">{{ field.label }}</label>
<div class="col-sm-10">
{{ field }}
<span class="help-block"> {{ field.errors.0 }}</span>
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">保存</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
3.私户和公户的转化
可以在视图函数中使用CBV的方式,再利用反射,实现功能
orm操作:
1. 公户变私户 # 方式一 查询的客户 models.Customer.objects.filter(pk__in=ids).update(consultant=self.request.user_obj) # models.Customer.objects.filter(pk__in=ids).update(consultant_id=self.request.session.get('pk')) # 方式二 查用户
self.request.user_obj.customers.add(*models.Customer.objects.filter(pk__in=ids))
2. 私户变公户 # 方式一 查询的客户 models.Customer.objects.filter(pk__in=ids).update(consultant=None) # 方式二 查用户 # self.request.user_obj.customers.remove(*models.Customer.objects.filter(pk__in=ids))
代码实现:
class CustomerList(View): def get(self, request, *args, **kwargs): if request.path_info == reverse('customer_list'): all_customer = models.Customer.objects.filter(consultant__isnull=True) else: all_customer = models.Customer.objects.filter(consultant=request.user_obj) page = Pagination(request.GET.get('page', 1), all_customer.count(), ) return render(request, 'customer_list.html', { 'all_customer': all_customer[page.start:page.end], 'page_html': page.page_html }) def post(self, request, *args, **kwargs): action = request.POST.get('action') # multi_apply multi_pub # 判断是否有相应的操作 if hasattr(self, action): # 有 获取并且执行 func = getattr(self, action) print(func) func() else: return HttpResponse('非法操作') return self.get(request, *args, **kwargs) def multi_apply(self, ): ids = self.request.POST.getlist('ids') # 把提交的客户的ID 都变成当前用户的私户 # 方式一 查询的客户 # models.Customer.objects.filter(pk__in=ids).update(consultant=self.request.user_obj) # models.Customer.objects.filter(pk__in=ids).update(consultant_id=self.request.session.get('pk')) # 方式二 查用户 self.request.user_obj.customers.add(*models.Customer.objects.filter(pk__in=ids)) def multi_pub(self): ids = self.request.POST.getlist('ids') # 把提交的客户的ID # 方式一 查询的客户 models.Customer.objects.filter(pk__in=ids).update(consultant=None) # 方式二 查用户 # self.request.user_obj.customers.remove(*models.Customer.objects.filter(pk__in=ids))
4.识别用户公户和私户的身份
采用中间件的方式进行认证,在login函数中,判定成功时加入session,使用对象的主键pk即可

中间件中这样验证, 采用白名单的形式
from django.utils.deprecation import MiddlewareMixin from crm import models from django.shortcuts import redirect, reverse class AuthMiddleware(MiddlewareMixin): def process_request(self, request): if request.path_info in [reverse('login'), reverse('reg')]: return if request.path_info.startswith('/admin/'): return pk = request.session.get('pk') user = models.UserProfile.objects.filter(pk=pk).first() # 没有登录 跳转至登录页面 if not user: return redirect(reverse('login')) request.user_obj = user
前端页面这样写
{% extends 'layout.html' %}
{% block content %}
<a class="btn btn-success btn-sm" style="margin: 3px" href="{% url 'customer_add' %}"> <i
class="fa fa-plus-square"></i> 添加 </a>
<form action="" method="post" class="form-inline">
{% csrf_token %}
<select name="action" id="" class="form-control">
{% if request.path_info == '/crm/my_customer/' %}
<option value="multi_pub"> 私户变公户</option>
{% else %}
<option value="multi_apply"> 公户变私户</option>
{% endif %}
<option value="multi_del"> 批量删除</option>
</select>
<button class="btn btn-sm btn-primary">提交</button>
<table class="table table-bordered table-hover">
<thead>
<tr>
<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>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for customer in all_customer %}
<tr>
<td>
<input type="checkbox" name="ids" value="{{ customer.pk }}">
</td>
<td>{{ forloop.counter }}</td>
<td>{{ customer.qq }}</td>
<td>{{ customer.name|default:'未填写' }}</td>
<td>{{ customer.get_sex_display }}</td>
{# <td>{{ customer.birthday|default:'未填写' }}</td>#}
{# <td>{{ customer.phone }}</td>#}
<td>{{ customer.get_source_display }}</td>
<td>{{ customer.course }}</td>
<td>
{{ customer.show_status }}
</td>
<td>{{ customer.last_consult_date }}</td>
<td>{{ customer.consultant }}</td>
{# <td>{{ customer.class_list.all }}</td>#}
<td>{{ customer.show_class }}</td>
<td>
<a href="{% url 'customer_edit' customer.pk %}"> <i class="fa fa-pencil-square-o"></i> </a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
{% endblock %}
5.其他
视图函数中,使用form表单时用到form_obj = MyForm(request,instance=obj)
由于视图函数文件中函数代码太多,所以在app中建一个views文件夹,里面放不同的py文件.原有的views.py文件删除
urls.py中添加编辑和新增的url

forms.py文件中添加需要用的表单,其中BootstrapForm类是因为方便统一为form组件的样式加入bootstap样式建立的,让其他表单继承这个类,将attrs属性加入这个类的__init__方法,其他的类只要继承就可以了,省下不少代码
# 定义Boostrap表单样式的类 class BootstrapForm(forms.ModelForm): def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) for field in self.fields.values(): field.widget.attrs.update({'class':'form-control'}) # Customer添加表单 class CustomerForm(BootstrapForm): class Meta: model = models.Customer fields = "__all__" def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) self.fields["course"].widget.attrs.pop('class')
现在将所有的有关用户的方法放进customer.py文件, 其中有新写的编辑,添加功能
form_obj = CustomerForm(request.POST,instance=obj)
上面这段代码是用来放进编辑功能的,私用instance=obj的方法可以将这个字段的数据直接放入表单,非常方便
customer.py
# 添加客户信息 def customer_add(request): form_obj = CustomerForm() if request.method == "POST": form_obj = CustomerForm(request.POST) print(form_obj.is_valid()) if form_obj.is_valid(): form_obj.save() return redirect(reverse('customer_list')) return render(request,"customer_add.html",{"form_obj": form_obj}) # 编辑客户 def customer_edit(request, edit_id): obj = models.Customer.objects.filter(pk=edit_id).first() # 处理POST if request.method == "POST": # 包含提交的数据 原始数据 form_obj = CustomerForm(request.POST,instance=obj) if form_obj.is_valid(): form_obj.save() return redirect(reverse('customer_list')) else: # 包含原始数据的form表单 form_obj = CustomerForm(instance=obj) return render(request, 'customer_edit.html', {"form_obj": form_obj})

浙公网安备 33010602011771号