CRM 流程 sweetalert弹框插件的使用

项目一 CRM

一丶设计表结构

from django.db import models
from multiselectfield import MultiSelectField
from django.utils.safestring import mark_safe

course_choices = (('Linux', 'Linux中高级'),
                ('PythonFullStack', 'Python高级全栈开发'),)

class_type_choices = (('fulltime', '脱产班',),
                    ('online', '网络班'),
                    ('weekend', '周末班',),)

source_type = (('qq', "qq群"),
              ('referral', "内部转介绍"),
              ('website', "官方网站"),
              ('baidu_ads', "百度推广"),
              ('office_direct', "直接上门"),
              ('WoM', "口碑"),
              ('public_class', "公开课"),
              ('website_luffy', "路飞官网"),
              ('others', "其它"),)

enroll_status_choices = (('signed', "已报名"),
                        ('unregistered', "未报名"),
                        ('studying', '学习中'),
                        ('paid_in_full', "已交齐"))

seek_status_choices = (('A', '近期无报名计划'), ('B', '1个月内报名'), ('C', '2周内报名'), ('D', '1周内报名'),
                      ('E', '定金'), ('F', '到班'), ('G', '全款'), ('H', '无效'),)

pay_type_choices = (('deposit', "订金/报名费"),
                  ('tuition', "学费"),
                  ('transfer', "转班"),
                  ('dropout', "退学"),
                  ('refund', "退款"),)

attendance_choices = (('checked', "已签到"),
                    ('vacate', "请假"),
                    ('late', "迟到"),
                    ('absence', "缺勤"),
                    ('leave_early', "早退"),)

score_choices = ((100, 'A+'),
                (90, 'A'),
                (85, 'B+'),
                (80, 'B'),
                (70, 'B-'),
                (60, 'C+'),
                (50, 'C'),
                (40, 'C-'),
                (0, ' D'),
                (-1, 'N/A'),
                (-100, 'COPY'),
                (-1000, 'FAIL'),)


class Department(models.Model):
   """
  部门表
  """
   name = models.CharField(max_length=32, verbose_name="部门名称")
   count = models.IntegerField(verbose_name="人数", default=0)

   def __str__(self):
       return self.name


class UserProfile(models.Model):
   """
  用户表
  """
   username = models.EmailField(max_length=255, unique=True, )
   password = models.CharField(max_length=128)
   name = models.CharField('名字', max_length=32)
   department = models.ForeignKey('Department', default=None, blank=True, null=True)
   mobile = models.CharField('手机', max_length=32, default=None, blank=True, null=True)
   memo = models.TextField('备注', blank=True, null=True, default=None)
   date_joined = models.DateTimeField(auto_now_add=True)
   is_active = models.BooleanField(default=True)

   def __str__(self):
       return self.name


class Customer(models.Model):
   """
  客户表
  """
   qq = models.CharField('QQ', max_length=64, unique=True, help_text='QQ号必须唯一')
   qq_name = models.CharField('QQ昵称', max_length=64, blank=True, null=True)
   name = models.CharField('姓名', max_length=32, blank=True, null=True, help_text='学员报名后,请改为真实姓名')
   sex_type = (('male', '男'), ('female', '女'))
   sex = models.CharField("性别", choices=sex_type, max_length=16, default='male', blank=True, null=True)
   birthday = models.DateField('出生日期', default=None, help_text="格式yyyy-mm-dd", blank=True, null=True)
   phone = models.BigIntegerField('手机号', blank=True, null=True)
   source = models.CharField('客户来源', max_length=64, choices=source_type, default='qq')
   introduce_from = models.ForeignKey('self', verbose_name="转介绍自学员", blank=True, null=True)
   course = MultiSelectField("咨询课程", choices=course_choices)
   class_type = models.CharField("班级类型", max_length=64, choices=class_type_choices, default='fulltime')
   customer_note = models.TextField("客户备注", blank=True, null=True, )
   status = models.CharField("状态", choices=enroll_status_choices, max_length=64, default="unregistered",
                             help_text="选择客户此时的状态")
   last_consult_date = models.DateField("最后跟进日期", auto_now_add=True)
   next_date = models.DateField("预计再次跟进时间", blank=True, null=True)
   consultant = models.ForeignKey('UserProfile', verbose_name="销售", related_name='customers', blank=True, null=True, )
   class_list = models.ManyToManyField('ClassList', verbose_name="已报班级", )

   def show_class(self):
       return ','.join([str(i) for i in self.class_list.all()])

   def show_status(self):
       status_dic = {
           'signed': 'green',
           'unregistered': 'red',
           'studying': 'pink',
           'paid_in_full': '#208ebc',
      }

       ret = f'<span class="btn" style="color: white; padding: 5px">{self.get_status_display()}</span>'
       return mark_safe(ret)

   def __str__(self):
       return f'{self.name}-{self.get_course_display()}-{self.get_status_display()}'


class Campuses(models.Model):
   """
  校区表
  """
   name = models.CharField(verbose_name='校区', max_length=64)
   address = models.CharField(verbose_name='详细地址', max_length=512, blank=True, null=True)

   def __str__(self):
       return self.name


class ClassList(models.Model):
   """
  班级表
  """
   course = models.CharField("课程名称", max_length=64, choices=course_choices)
   semester = models.IntegerField("学期")
   campuses = models.ForeignKey('Campuses', verbose_name="校区")
   price = models.IntegerField("学费", default=10000)
   memo = models.CharField('说明', blank=True, null=True, max_length=100)
   start_date = models.DateField("开班日期")
   graduate_date = models.DateField("结业日期", blank=True, null=True)
   teachers = models.ManyToManyField('UserProfile', verbose_name="老师")
   class_type = models.CharField(choices=class_type_choices, max_length=64, verbose_name='班额及类型', blank=True,
                                 null=True)

   class Meta:
       unique_together = ("course", "semester", 'campuses')

   def __str__(self):
       return '{}{}{}'.format(self.get_course_display(), self.semester, self.campuses)


class ConsultRecord(models.Model):
   """
  跟进记录表
  """
   customer = models.ForeignKey('Customer', verbose_name="所咨询客户")
   note = models.TextField(verbose_name="跟进内容...")
   status = models.CharField("跟进状态", max_length=8, choices=seek_status_choices, help_text="选择客户此时的状态")
   consultant = models.ForeignKey("UserProfile", verbose_name="跟进人", related_name='records')
   date = models.DateTimeField("跟进日期", auto_now_add=True)
   delete_status = models.BooleanField(verbose_name='删除状态', default=False)


class Enrollment(models.Model):
   """
  报名表
  """

   why_us = models.TextField("为什么报名", max_length=1024, default=None, blank=True, null=True)
   your_expectation = models.TextField("学完想达到的具体期望", max_length=1024, blank=True, null=True)
   contract_agreed = models.BooleanField("我已认真阅读完培训协议并同意全部协议内容", default=False)
   contract_approved = models.BooleanField("审批通过", help_text="在审阅完学员的资料无误后勾选此项,合同即生效", default=False)
   enrolled_date = models.DateTimeField(auto_now_add=True, verbose_name="报名日期")
   memo = models.TextField('备注', blank=True, null=True)
   delete_status = models.BooleanField(verbose_name='删除状态', default=False)
   customer = models.ForeignKey('Customer', verbose_name='客户名称')
   school = models.ForeignKey('Campuses')
   enrolment_class = models.ForeignKey("ClassList", verbose_name="所报班级")

   class Meta:
       unique_together = ('enrolment_class', 'customer')


class PaymentRecord(models.Model):
   """
  缴费记录表
  """
   pay_type = models.CharField("费用类型", choices=pay_type_choices, max_length=64, default="deposit")
   paid_fee = models.IntegerField("费用数额", default=0)
   note = models.TextField("备注", blank=True, null=True)
   date = models.DateTimeField("交款日期", auto_now_add=True)
   course = models.CharField("课程名", choices=course_choices, max_length=64, blank=True, null=True, default='N/A')
   class_type = models.CharField("班级类型", choices=class_type_choices, max_length=64, blank=True, null=True,
                                 default='N/A')
   enrolment_class = models.ForeignKey('ClassList', verbose_name='所报班级', blank=True, null=True)
   customer = models.ForeignKey('Customer', verbose_name="客户")
   consultant = models.ForeignKey('UserProfile', verbose_name="销售")
   delete_status = models.BooleanField(verbose_name='删除状态', default=False)

   status_choices = (
      (1, '未审核'),
      (2, '已审核'),
  )
   status = models.IntegerField(verbose_name='审核', default=1, choices=status_choices)

   confirm_date = models.DateTimeField(verbose_name="确认日期", null=True, blank=True)
   confirm_user = models.ForeignKey(verbose_name="确认人", to='UserProfile', related_name='confirms', null=True,
                                    blank=True)


class CourseRecord(models.Model):
   """课程记录表"""
   day_num = models.IntegerField("节次", help_text="此处填写第几节课或第几天课程...,必须为数字")
   date = models.DateField(auto_now_add=True, verbose_name="上课日期")
   course_title = models.CharField('本节课程标题', max_length=64, blank=True, null=True)
   course_memo = models.TextField('本节课程内容', max_length=300, blank=True, null=True)
   has_homework = models.BooleanField(default=True, verbose_name="本节有作业")
   homework_title = models.CharField('本节作业标题', max_length=64, blank=True, null=True)
   homework_memo = models.TextField('作业描述', max_length=500, blank=True, null=True)
   scoring_point = models.TextField('得分点', max_length=300, blank=True, null=True)
   re_class = models.ForeignKey('ClassList', verbose_name="班级")
   teacher = models.ForeignKey('UserProfile', verbose_name="讲师", related_name='courserecords')
   recorder = models.ForeignKey('UserProfile', verbose_name="记录者")

   class Meta:
       unique_together = ('re_class', 'day_num')


class StudyRecord(models.Model):
   """
  学习记录
  """

   attendance = models.CharField("考勤", choices=attendance_choices, default="checked", max_length=64)
   score = models.IntegerField("本节成绩", choices=score_choices, default=-1)
   homework_note = models.CharField(max_length=255, verbose_name='作业批语', blank=True, null=True)
   date = models.DateTimeField(auto_now_add=True)
   note = models.CharField("备注", max_length=255, blank=True, null=True)
   homework = models.FileField(verbose_name='作业文件', blank=True, null=True, default=None)
   course_record = models.ForeignKey('CourseRecord', verbose_name="某节课程")
   student = models.ForeignKey('Customer', verbose_name="学员")

   class Meta:
       unique_together = ('course_record', 'student')
### 步骤:
# 1. 创建数据库,
   # 2. settings配置数据库,__init__连接数据库
   # 3. 执行迁移命令

 

二丶登录和注册

登录

# 1. 从jq22网站上 爬取一个登录页面
# 2. 配置静态文件static
# 3. 写路由匹配规则CBV或FBV (路由分发,名称空间,反向解析)
# 4. 编写视图函数(登录的业务逻辑)
# 4.1 获得提交的帐号和密码
# 4.2 从数据库查询
# 4.3 成功跳转页面,不成功返回登录页面

注册

# 1.爬取注册页面
# 2.配置static文件
# 3.编写路由规则
# 4.编写视图函数
# 4.1 使用forms组件生成前端页面的文本框
# 4.1.1 导入forms组件
# 4.1.2 自定义form组件的文本框 具有覆盖重写widgets中的文本框效果
      password = forms.CharField(
               min_length=6, # 指定约束的最小值
               # 指定类型
               widget=forms.PasswordInput(attrs={'placeholder': '请输入密码', }),
          )
       
       
# 4.1.3 ModelForm组件 表模型和form组件结合
           class Meta:
              model = models.UserProfile # 指定使用哪张表
               fields = '__all__'  # 全局的字段
               exclude = ['is_active']  # 不包含哪些字段
               
      widgets={  #要生成的form文本框
               
          }
       
       
# 4.1.4 使用全局'钩子'对确认密码进行校验
      def clean(self):  
               self._validate_unique = True  # 表示唯一性约束
               
               password = self.cleaned_data.get('password','')
               re_password = self.cleaned_data.get('re_password')
               
               
               if password == re_password:  # 判断密码一致时
                   md = hashlib.md5() # md5 加密对象
                   md.update(password.encode('utf-8')) # 给字符串进行加密
                   self.cleaned_data['password'] = md.hexdigest()  # 给所有的键值对cleaned_data设置md5的密码值
                   return self.cleaned_data  # 所有的键值对
               self.add_error('re_password', '两次密码不一致')  # 给add_error方法添加错误
               raise ValidationError('两次密码不一致')  # 主动抛出异常

 

三丶展示客户列表

### 使用 模版语言的过滤器进行过滤
# 1. 使用给定的字段方法 get_字段_display 针对于choice类型的字段 如:get_sex_display
# 2. 自定义方法 如:show_status
<tbody>
{% for customer in all_customers %}
   <tr>
       <td>{{ forloop.counter }}</td>  
       <td>{{ customer.qq }}</td>
       <td>{{ customer.name|default:'-' }}</td>
       <td>{{ customer.get_sex_display|default:'-' }}</td>
       <td>{{ customer.phone|default:'-' }}</td>
       <td>{{ customer.get_source_display|default:'-' }}</td>
       <td>{{ customer.get_course_display|default:'-' }}</td>
       <td>
          {{ customer.show_status|default:'-' }}  
       </td>
       <td>{{ customer.next_date|date:'Y-m-d'|default:'-' }}</td>
       <td>{{ customer.consultant|default:'-' }}</td>
       <td>
          {% for class in customer.class_list.all %}
              {{ class.name|default:'-' }}
          {% endfor %}
       </td>
   </tr>
{% endfor %}

</tbody>



### models中 自定义方法, 变更状态的显示
   def show_status(self):
       status_dic = {
           'signed': 'green',
           'unregistered': 'red',
           'studying': 'pink',
           'paid_in_full': '#208ebc',
      }

       ret = f'<span class="btn" style="color: white; padding: 5px">{self.get_status_display()}</span>'
       return mark_safe(ret)

 

四丶添加客户信息

使用forms组件生成文本框

class CustomerForm(forms.ModelForm):

   def __init__(self,*args,**kwargs): # 可以给字段自定制一些额外的属性和操作
       super().__init__(*args,**kwargs) # 执行父类的方法
       
       ### 可以针对每一个/某一类字段对象 , 进行样式的更改
       for name,field in self.fields.items():
  #### 解释: field 是每一个字段的对象, name 是字段的名称
           
           if isinstance(field,(MultiSelectFormField)):  # 判断form字段对象是不是属于多选框类型,属于则不添加class属性
               continue
               
           field.widget.attrs['class']='form-control' # 给字段的widget属性添设置attrs属性,通过键值对的形式,最终展示在页面上的效果.如: <input class='form-control' />
           field.widget.attrs['placeholder']='请填写{}'.format(field.__dict__['label'])


   class Meta:
       model = models.Customer # 绑定使用哪一个models
       fields = '__all__' # 绑定使用的字段

页面显示

<div class="panel panel-info">
       <div class="panel-heading">
           <h3 class="panel-title">{{ title }}</h3>
       </div>
       <div class="panel-body">
           <form class="form-horizontal" action="" method="post" novalidate>
               {% csrf_token %}
               
              ### 通过循环 可以拿到每一个字段对象
               {% for cus_obj in customer_form_obj %}
              # 判断是否存在错误信息,存在则添加上样式.反之亦然
                   <div class="form-group  {% if cus_obj.errors.0 %}has-error{% endif %}">
                      # label属性 , 或者是verbose_name属性的值
                      # cus_obj.field.required 通过字段对象得到field属性的required属性
                       <label for="{{ cus_obj.id_for_label }}"
                              class="col-sm-2 control-label {% if not cus_obj.field.required %} not_required {% endif %}">{{ cus_obj.label }}</label>
                       <div class="col-sm-8">
                          # 生成每一个标签对象
                           {{ cus_obj }}
                       </div>
                      # 错误信息 errors是一个错误列表,取第一条错误信息即可.
                       <span class="help-block text-danger">{{ cus_obj.errors.0 }}</span>
                   </div>
               {% endfor %}

               <div class="form-group">
                   <div class="col-sm-offset-3 col-sm-9">
                       <button type="submit" class="btn btn-default">保存</button>
                   </div>
               </div>
           </form>
       </div>
   </div>

添加数据

### forms组件,自动填充数据,自动添加数据. 都是封装好的.
def customer_add(request):
   customer_form_obj = CustomerForm()
   
   if request.method == 'POST':
       customer_form_obj = CustomerForm(request.POST) # forms组件自动填充数据
       if customer_form_obj.is_valid(): # forms校验
           customer_form_obj.save() # 自动保存数据
           return redirect('crm:customer_list')

   return render(request, 'customer_add.html', {'customer_form_obj': customer_form_obj})

数据展示

##数据展示

1. 普通字段
   对象.字段名   ——》  数据库的值
    
2. choices
   对象.字段名   ——》  数据库的值
   对象.get_字段名_display()   ——》 对应显示的值

3. 外键
   对象.外键   ——》  关联的对象  __str__
   对象.外键.字段  

4. 自定义方法
	def show_class(self):
        return ' , '.join([str(i) for i in self.class_list.all()])
    返回html页面
    from django.utils.safestring import mark_safe  

 

五丶编辑和新增同理

### urls.py
    ##### 统一函数, 添加和保存都可使用同一个是视图函数
    url(r'^customer_add/', views.customer_change, name='customer_add'),
    url(r'^customer_edit/(\d+)', views.customer_change, name='customer_edit'),


### 可以使用同一个视图函数
def customer_change(request, pk=None): 
    
    cur_obj = models.Customer.objects.filter(pk=pk).first()
    
    customer_form_obj = CustomerForm(instance=cur_obj) # instance携带当前对象,进行编辑展示
    
    if request.method == 'POST':
        customer_form_obj = CustomerForm(request.POST, instance=cur_obj)
        if customer_form_obj.is_valid():
            customer_form_obj.save()
            return redirect('crm:customer_list')
        
    title='添加客户' if pk else '编辑客户'
    
    return render(request, 'customer_change.html', {'customer_form_obj': customer_form_obj,
    			'title':title})


六丶公户和私户(登录认证)

登录认证

### 自定义中间件
	# 1.在app下创建中间件文件夹 和 自定义中间件py文件
	# 2.注册中间件,settings配置
	# 3.重启项目
    
from django.shortcuts import reverse,redirect
from django.utils.deprecation import MiddlewareMixin

class MyMiddleware(MiddlewareMixin):

    def process_request(self,request):

        ###  url  白名单
        urls=[reverse('crm:login'),reverse('crm:register')]

        if request.path_info in urls:	# 请求路径在 白名单内不进行认证
            return

        if request.path_info.startswith('/admin/'): # admin系统不进行认证
            return

        if request.session.get('is_login')!='1': # 登录认证
            return redirect('crm:login')
		
        ## 查询用户表的数据 ,用于做私户
        obj=models.UserProfile.objects.filter(pk=request.session.get('user_id'))
        if obj:
            # 封装到 request对象中属性
            request.user_obj=obj

公户私户查询

def customer_list(request):
    customer_form_obj = CustomerForm()
    # 依据请求的路径判断公私户
    if request.path_info==reverse('crm:customer_list'): 
        # 公户 没有用户跟随  consultant字段是None
        all_customers = models.Customer.objects.filter(consultant_id__isnull=True)
        				.reverse().order_by('status').reverse()
    else:
        # 私户 根据 用户表查询的对象, 根据request对象封装的属性查询数据
        all_customers = models.Customer.objects.filter(consultant=request.user_obj)
        				.order_by('status')

    curPage = request.GET.get('page')
    page_customer_obj = Pagetions(curPage, len(all_customers), page_nums=10, max_show=7)
    return render(request, 'customer_list.html',
                  {'all_customers': all_customers[page_customer_obj.start:page_customer_obj.end],
                   'page_html': page_customer_obj.page_html(),'customer_form_obj':customer_form_obj})

七丶分页

# 对于数据来说, 获取当前页,计算显示的数据条目数
	# 切片起始位置 = (当前页-1)*每页显示的条目数
	# 切片结束位置 = 当前页*每页显示的条目数	
	
	

# -*-coding:utf-8-*-
# Author:Ds
from django.utils.safestring import mark_safe
from django.http.request import QueryDict


### 分页使用
	'''
	参数解释:
		当前页 : request.GET.get('page')
		所有数据:all_courses_record.count()
		QueryDict对象(携带参数信息): request.GET.copy()  # 深拷贝,不影响原request.GET的使用
		屏幕显示页码数:
		每页显示的数据条目数:
		
	'''
page_obj = Pagetions(request.GET.get('page'), all_courses_record.count(), request.GET.copy(), 3, 3)


### 分页功能, 抽取成类
class Pagetions:

    def __init__(self, curPage, all_data, params=None, page_nums=10, max_show=9):
        '''
        :param curPage:   # 当前页数
        :param all_data:  # 数据总量
        :param page_nums:  # 每页多少条
        :param max_show:  # 显示总共几页
        '''


		### 保留分页的条件信息
        # 需要 拼接参数, 使用QueryDict 的urlencode方法,将参数 拼接, 并转码
        if not params:
            params=QueryDict(mutable=True) # 能够修改 QueryDict
        self.params=params
        # 1. 给self对象附上属性
        try:
            # 处理传递的当前页.  转换类型数值型
            curPage = int(curPage)
            if curPage < 0:
                curPage = 1
        except Exception:
            curPage = 1

        self.curPage = curPage  # 当前页
        self.all_data = all_data  # 总数据量

        # 2. 分页计算
        #  计算总页数
        total_num, more = divmod(all_data, page_nums)  # 总数据量  每页显示几条

        if more:  # 当数据不能显示完一页,多余几条, 必须个增加一页去进行显示
            total_num += 1

        # 3. 最大显示的页码数的一边,用于固定页码的数量
        half_show = max_show // 2

        # 4. 分页边界判断
        if total_num <= max_show:
            ### 总页数不超过 最大页码数
            page_start = 1  # 起始页
            page_end = total_num  # 终止页
        else:
            ### 总页数超过最大页码数
            ## 左极值
            if self.curPage - half_show <= 0:  # 当前页  小于 最大显示的页数
                page_start = 1  # 起始页
                page_end = max_show  # 终止页  一页显示的总页数

                ## 右极值
            elif self.curPage + half_show > total_num:  # 当前页的页数 大于 最大显示的页数
                page_start = total_num - max_show + 1  # +1  总页数-一屏幕显示几页+1
                page_end = total_num  # #  总页数

            else:
                ## 正常
                # 页码的起始位置
                page_start = self.curPage - half_show  # 起始位置 = 当前页 -最大显示的页码数
                # 页码的终止位置
                page_end = self.curPage + half_show  # 结束位置 = 当前页 +最大显示的页码数

        self.page_start = page_start
        self.page_end = page_end
        self.total_num = total_num

        ### 切片显示数据
        self.start = (self.curPage - 1) * page_nums
        self.end = self.curPage * page_nums


    def page_html(self):
        '''
        ## 此方法用于生成 前一页 和 后一页
        :return:
        '''
        # 存放生成的html字符串
        li_list = []
		
        # 左极值
        if self.curPage == 1:
            # 第一页
            li_list.append(
                '<li class="disabled"><a aria-label="Previous"> <span aria-hidden="true">&laquo;</span></a></li>'
            )
        else:
            self.params['page']=self.curPage-1  #
            li_list.append(
                f'<li><a href="?{self.params.urlencode()}" aria-label="Previous"> <span aria-hidden="true">&laquo;</span></a></li>'
            )
		
        ### 生成页码 
        for el in range(self.page_start, self.page_end + 1):
            # 修改QueryDict的page字段的值
            self.params['page']=el
            
            if el == self.curPage: # 被选中
                li_list.append('<li class="active"><a href="?{}">{}</a></li>'.format(self.params.urlencode(), el))
            else:
                li_list.append('<li><a href="?{}">{}</a></li>'.format(self.params.urlencode(), el))

        # 右极值      
        if self.curPage <= self.total_num:
            
            li_list.append( # 不可编辑
                '<li class="disabled"><a aria-label="Previous"> <span aria-hidden="true">&raquo;</span></a></li>'
            )
        else:
            
            self.params['page']=self.curPage+1

            li_list.append(
                '<li><a href="?{}" aria-label="Previous"> <span aria-hidden="true">&raquo;</span></a></li>'.format(self.params.urlencode())
            )

        return mark_safe(''.join(li_list))

八丶模糊查询

### 使用GET方式提交数据,往当前页提交数据.

<form action="" class="form-inline pull-right">
    <input type="text" class="form-control" name="search" placeholder="搜索...">
    <button type="submit" class="btn btn-success">搜索</button>
</form>
## CBV模式 
	# post提交表单数据
def post(self, request):
        action = request.POST.get('action')

        if not hasattr(self, action):
            return HttpResponse('无效操作')

        self.choice_id = request.POST.getlist('choice_id')

        ## 反射执行具体的方法
        ret=getattr(self, action)()

        if ret:
            return ret

        return self.get(request)

    # 模糊查询数据,根据Q条件
def get(self, request, class_id, *args, **kwargs):
     # get  列表的形式传递查询字段
	 q = self.search(['campuses__name', 'start_date'])
    
     # 查询数据时,将q对象放到filter方法中,作为关键字参数
	 all_class = models.ClassList.objects.filter(q, )


	# 设置Q查询,
def search(self, field_list):
        # 获取查询的信息
        search = self.request.GET.get('search', '')
        
        q = Q() 
        q.connector = 'OR'  # 设置类型 '或'条件  

        ## 方式一 直接添加Q对象  关键字
        q.children.append(Q(qq__contains=search))
        
        

        ## 方式二  元组   字符串
        for field in field_list:  # 
            # 元组形式,可以操作字符换 ('{}__contains'.format(field), search)
            q.children.append(Q(('{}__contains'.format(field), search)))

        return q

九丶编辑和添加跳转原页面

# 1. 携带下次跳转的页面信息
@register.simple_tag
def url_revers(request,name,*args,**kwargs):

    url=reverse(name,args=args,kwargs=kwargs) #  根据url的name属性,反向解析出URL链接
    
    next=request.get_full_path() # 获得全路径

    qd=QueryDict(mutable=True) # QueryDict设置,保留参数字段
    # 由于?后的参数都不会被保存,所以再Django中必须使用QueyrDict中的urlencode对url的参数进行编码解析
    # next的是url地址中?的参数. next=%2Fcrm%2Fone_enrollment_list%
    	# 2F1%2F%3Fnext%3D%252Fcrm%252Fmy_customer_list%252F
    qd['next']=next	# 设置next属性

    return '{}?{}'.format(url,qd.urlencode())
# 使用自定义的标签
<a href="{% url_revers request 'crm:consultrecord_edit' consulrecord.pk %}" class="btn btn-warning">编辑</a>
# 自定义标签 
	# 创建一个名为templatetags的python包 名字必须是templatetags
    # 导入固定写法
    
    
# -*-coding:utf-8-*-
# Author:Ds
from django import template
from django.urls import reverse  # 用于反向解析URL
from django.http.request import QueryDict # 参数编码
register=template.Library() # 固定写法

@register.simple_tag
def url_revers(request,name,*args,**kwargs):
	'''
	参数解释:
		request:传递的request请求对象, 获得路径
		name:需要跳转页面的name字符串, 由reverse反向解析可以获得请求的URL
		args:接收其他的位置参数
		kwargs:接收其他的关键字参数
	'''
    url=reverse(name,args=args,kwargs=kwargs) # 通过name,反向解析URL
    
    # 获得 当前请求的请求路径
    next=request.get_full_path()
	
    # 实例化一个qd对象
    qd=QueryDict(mutable=True)
    qd['next']=next # 对qd对象进行封装属性,封装下一次要跳转的URL路径.
    
    
	# 返回一个字符串路径,通过 qd对象的 urlencode 方法, 把路径进行编码.
    # 如:'http://127.0.0.1:8000/crm/class_edit/1?next=%2Fcrm%2Fclass_list%2F'
    return '{}?{}'.format(url,qd.urlencode())  

十丶新增和编辑的选择数据是当前用户的数据

class EnrollmentForm(BSForm):
    class Meta:
        model = models.Enrollment
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        customer_obj = self.instance.customer
		
        ### fields的是一个字典. choices是 choices字段进行限制, 
        ### 值必须是元组形式. 
        
        # 编辑时,限制是当前客户
        self.fields['customer'].choices = [(customer_obj.pk, customer_obj), ]
        # 限制是自己所选的班级。
        self.fields['enrolment_class'].choices = [('', '---------')] + [(i.pk, str(i)) for i in customer_obj.class_list.all()]

十一丶公私户的转换

###完整版
def mutli_apply(self):
        ### 公户转私户
        # 方式一
        # 通过 客户关联销售
        my_customer_count=models.Customer.objects.filter(consultant=self.request.user_obj).count()
        ## 判断私户上限
        if my_customer_count+len(self.choice_id)>settings.MAX_CUSTOMER_NUM:
            extra=int(settings.MAX_CUSTOMER_NUM) - int(my_customer_count)
            print(extra)
            return HttpResponse(f'做人不能太贪心,给别人留一点,您的剩余名额还有{extra}')

        try:
            with transaction.atomic():
                ## 添加  行级锁 select_for_update()  ,对条件进行进一步限制.
                queryset=models.Customer.objects.filter(pk__in=self.choice_id,consultant=None).select_for_update()
                # 当查询出来的数据 , 和提交的数据量一致 . 才进行更新
                if len(self.choice_id)==queryset.count():
                    queryset.update(consultant=self.request.user_obj)
                else:
                    return HttpResponse('手速太慢了,更改无效')

        except Exception as e:
            print(e)
        # 方式二
        # 通过销售添加客户   #self.request.user_obj.customers.add
        	(*models.Customer.objects.filter(pk__in=self.choice_id))

 

补充

一丶sweetalert弹框插件的使用

网址 https://sweetalert.js.org/

//  sweetalert的使用
// 1.引入 sweetalert 的js文件
// 2.编写js文件
$('.del-cus').click(function () {
    cur_obj = $(this);

    swal({
        title: "确定要删除吗?",
        text: "一旦删除将不可恢复!" ,
        icon: "warning",
        buttons: ['取消', '删除'],
        dangerMode: true,
    })
        .then((willDelete) => {
            if (willDelete) {
                // 异步ajax删除
                $.ajax({
                    url: 'XXX', // 请求路径
                    success: function (data) { // 执行完业务返回的结果
                        if (data){
                            // 1.移除页面显示数据
                           
                            // 2.刷新页面
                           
                        }
                    }
                })

                swal("删除成功!", {
                    icon: "success",
                });
            } else {
                swal("你取消了删除!");
            }
        });
})

 

二丶分页

# python的分页 

 

posted on 2020-03-02 12:22  向往1  阅读(203)  评论(0编辑  收藏  举报

导航

……