• CRM-项目


    CRM项目:

    customer relationship management

    需求分析

    • 使用系统的人员
      • 销售 财务 班主任 项目经理
    • 需求分析:
      • 注册
      • 登陆
    • 销售:
      • 客户信息的管理
        • 增加、编辑、查看客户信息
      • 跟进记录的管理
        • 增加、编辑、查看跟进记录
      • 报名记录的管理
        • 增加、编辑、查看报名记录
      • 缴费的记录
        • 增加、编辑、查看缴费记录
    • 班主任:
      • 班级的管理
        • 增加、编辑、查看班级的信息
      • 课程记录
        • 增加、编辑、查看课程记录
      • 学习记录表
        • 增加、编辑、查看课程记录

    表结构的设计

    1. 用户表

    2. 客户表

    3. 跟进记录表

    4. 报名表

    5. 缴费记录表

    6. 校区表

    7. 班级表

    8. 课程记录

    9. 学习记录表

    • 下载 pip install django-multiselectfield

    登录注册功能

    • views

      from django.shortcuts import render,redirect,HttpResponse 
      from crm import models 
      import hashlib 
      
      
      def login(request):
          if request.method == 'POST':
              user = request.POST.get('username')
              pwd = request.POST.get('password')
       
              md5 = hashlib.md5()               #将密码加密验证
              md5.update(pwd.encode('utf-8'))
              pwd = md5.hexdigest()
              obj = models.UserProfile.objects.filter(username=user,password=pwd,is_active=True).first()
       
              if obj:   #obj查询没有结果为none
                  return redirect('crm:customer')
              return render(request, 'login.html',{'error':'用户名密码错误'})
          return render(request,'login.html')
       
       
      from django import forms             #forms组件
      from django.core.exceptions import ValidationError
       
      class RegForm(forms.ModelForm):
          password = forms.CharField(min_length=6,widget=forms.PasswordInput(
              attrs={'placeholder':'密码','autocomplete':'off'}))   #自定义会覆盖默认的
          re_password = forms.CharField(min_length=6,widget=forms.PasswordInput(
              attrs={'placeholder':'确认密码','autocomplete':'off'}))        #新增字段
       
       
          class Meta:                      #生成默认字段
              model = models.UserProfile
              fields = '__all__'  #所有字段在前端展示form组件,所有字段使用['username','password']
              exclude = ['is_active']      #排除字段,生成时候没有,默认使用数据库中的默认值
       
              widgets={                    #默认字段对应的插件,添加属性
                  'username':forms.TextInput(attrs={'placeholder':'用户名','autocomplete':'off'}),
                  'password':forms.PasswordInput(attrs={'placeholder':'密码','autocomplete':'off'}),
                  'name':forms.TextInput(attrs={'placeholder':'真是姓名','autocomplete':'off'}),
                  'mobile':forms.TextInput(attrs={'placeholder':'手机号','autocomplete':'off'}),
              }
      
              error_messages={
                  'username':{
                      'unique':'用户名相同重新输入'
                  }
              }
      
          def clean(self):  #全局钩子
              self._validate_unique = True   #到数据库效验唯一性,前端会展示数据已经存错误
              password = self.cleaned_data.get('password')
              re_password = self.cleaned_data.get('re_password')
      
              #判断两次密码是否一致,是将数据返回,and前面为判断是否为空
              if password and password == re_password:     
                  md5 = hashlib.md5()
                  md5.update(password.encode('utf-8'))
                  self.cleaned_data['password'] = md5.hexdigest()  #将密码修改为加密后的
                  return self.cleaned_data
      
              self.add_error('re_password','两次密码不一致!')  #加入到指定字段显示错误
              raise ValidationError('两次密码不一致')
      
      
      
      def reg(request):          #注册账号
          form_obj = RegForm()   #实例化对象
      
          if request.method == 'POST':
              form_obj = RegForm(request.POST)
              # print(form_obj)
              if form_obj.is_valid():             #获取form表单进行效验
                  form_obj.save()
                  return redirect('crm:login')    #数据写入后完,跳转至登录页面
      
              # print(form_obj.cleaned_data)
          return  render(request,'reg.html',{'form_obj':form_obj})
      

    • login.html

          <form action="" method="post">
              {% csrf_token %}
              <div>
                  <input type="text" name="username" class="username" placeholder="输入账号" autocomplete="off">
              </div>
              <div>
                  <input type="password" name="password" class="password" placeholder="输入密码" oncontextmenu="return false"
                         onpaste="return false">
              </div>
              <div>{{ error }}</div>
              <button id="submit" >登录</button>
      
          </form>
      

    展示数据:

    • 展示方法

      • 普通字段

        #对象.字段名   ——》  数据库的值
        <td>{{ customer.qq }}</td>
        

      • choices

        #对象.字段名   ——》  数据库的值
        #对象.get_字段名_display()   ——》 对应显示的值
        <td>{{ customer.get_source_display }}</td>
        

      • 外键

        #对象.外键   ——》  关联的对象  __str__
        #对象.外键.字段  
        <td>{{ customer.consultant.name }}</td>    #consultant外键
        

      • 多对多

        <td>{% for foo in customer.class_list.all %}
            {{ foo.get_course_display }}
            {% endfor %}
        </td>
        

      • 自定义model方法

        from django.utils.safestring import mark_safe   #前端html不转义
        
        #前端调用:
        <td>{{ customer.show_status }}</td>
        
        #models
            def show_status(self):
                color_dict = {
                    'signed': 'green',
                    'unregistered':'red',
                    'studying': 'pink',
                    'paid_in_full':'gold'
                }
                return mark_safe(f'<span style="color: white;background-color: {color_dict.get(self.status)};padding: 3px">{self.get_status_display()}</span>')
        
        

      模糊查询

      Q((Q(qq__contains=query) | Q(name__contains=query) )
      
      q = Q()
      q.connector = 'OR'
      q.children.append(Q(qq__contains=query))
      q.children.append(Q(name__contains=query))
      
      Q(qq__contains=query)   Q(('qq__contains',query))
      

      分页的问题

      request.GET    QueryDict  默认不可修改
      request.GET._mutable = True
      request.GET['page'] = 1
      
      QueryDict(mutable=True)  可修改的字典
      request.GET.copy()       深拷贝  可修改
      
      request.GET.urlencode()     {query:123,page:2}   _>   query=123&page=2
      
      

      编辑后跳转到原页面

      生成url地址

      @register.simple_tag
      def url_tag(request,name,*args,**kwargs):
          url = reverse(name,args=args,kwargs=kwargs)
      
          next = request.get_full_path()
      
          qd = QueryDict(mutable=True)
          qd['next']=next
      
          return "{}?{}".format(url,qd.urlencode())
      
      

      编辑保存后跳转到原页面

      next = request.GET.get('next')
      if next:
          return redirect(next)
      return redirect('crm:customer_list')
      
      

    权限

    • 用户登录成功,查询权限信息,也就是查询权限路径

      #去空去重
      permissions = user_obj.roles.filter(permissions__url__isnull=False).values('permissions__url').distinct()
      
      #user_obj.roles permissions__url 
      #获取到的是当前登录成功的用户对象,通过用户对象,找到用户角色,在用双下方法查找当前url权限有多少
      
      

    • 将路径信息保存在session中

      #query_set默认不可json序列化
      request.session['permissions'] = list(permissions) 
      
      #登录状态保存在session中
      request.session['is_login'] = True   #保存登录状态
      
      

    • 获取页面路径,进行效验:

      class RbacMiddleWare(MiddlewareMixin):
      
          def process_request(self,request):
              url = request.path_info                #获取当前访问的地址
      
      
              for i in settings.WHITE_LIST:          #白名单校验,判断url中是否含有login
                  if re.match(i,url):                #i正则匹配url是否跟自己匹配
                      return
      
              is_login = request.session.get('is_login')  #没有登录状态,重新登录
              if not is_login:
                  return redirect('login')
      
      
              for i in settings.PASS_AUTH_LIST:           #免认证登录,不需要权限,如首页
                  if re.match(i,url):
                      return
      
              permissions = request.session.get('permissions')   #获取权限信息
              for i in  permissions:                       #判断访问的地址是否跟权限中地址匹配成功
                  if re.match(r'^{}$'.format(i['permissions__url']), url):
                      return
      
              return HttpResponse('没有访问权限,练习管理员')  #效验全部不通过,拒绝请求
      
      
  • 相关阅读:
    【异常】org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter '**' not found.的解决办法
    java如何进行字符串拼接?
    poj2352消防站
    NOIP第7场模拟赛题解
    转载:
    usaco 2010年3月银组题解
    Js 向json对象中添加新元素
    List<T>中 GetRange (int index, int count)的使用
    C# string格式的日期时间字符串转为DateTime类型
    C# DataTable转List<T>--利用反射
  • 原文地址:https://www.cnblogs.com/haiyang11/p/11688542.html
Copyright © 2020-2023  润新知