zoukankan      html  css  js  c++  java
  • 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('没有访问权限,练习管理员')  #效验全部不通过,拒绝请求
      
      
  • 相关阅读:
    【Javascript】javascript学习 二十二 JavaScript 对象简介
    【Javascript】javascript学习 二十六 JavaScript Boolean(逻辑)对象
    【Javascript】javascript学习 二十九 JavaScript HTML DOM 对象
    【Javascript】javascript学习 二十八 JavaScript RegExp 对象
    【Javascript】javascript学习 二十一 JavaScript 指导方针
    【Javascript】javascript学习 二十三 JavaScript 字符串(String)对象
    【Javascript】javascript学习 三十 JavaScript 浏览器检测
    【Javascript】javascript学习 二十五 JavaScript Array(数组)对象
    【Javascript】javascript学习 二十四 JavaScript Date(日期)对象
    【Javascript】javascript学习 二十七 JavaScript Math(算数)对象
  • 原文地址:https://www.cnblogs.com/haiyang11/p/11688542.html
Copyright © 2011-2022 走看看