zoukankan      html  css  js  c++  java
  • CRM项目表结构设计、登录注册、展示数据、删除、分页、搜索、编辑跳转、自定义simple_tag、事务 + 行级锁、批量初始化学习记录、每次请求 都做权限的校验、动态生成一级菜单、动态生成二级菜单、非菜单的权限的归属的问题

    CRM

    客户关系管理系统

    表结构的设计

    • 客户表

    • 用户表

    • 校区表

    • 部门表

    销售

    • 跟进记录表

    • 报名表

    • 缴费表

    班主任

    • 班级表

    • 课程记录表

    • 学习记录表

    登录注册

    注册—— modelform

     from django import forms
     
     class Form(forms.ModelForm):
      class Meta:
      model = models.xxx
      fields = "__all__"  # ['name','pwd']
      exclude = ['is_active']
     
      def clean_字段名(self)
      # 校验规则
             # 通过 返回当前字段的值
             # 不通过 抛出异常
             # raise ValidationError('xx')
             
           
        def clean(self)
      # 校验规则
             # 通过 返回所有字段的值 self.cleaned_data
             # 不通过 抛出异常
             # self.add_error('re_password', '两次密码不一致!!')
             # raise ValidationError('xx') "__all__"
     
         def __init__(self, *args, **kwargs):
             super().__init__(*args, **kwargs)
             # 自定义的操作
             for name, field in self.fields.items():
                 # print(name, field)
                 if isinstance(field, (forms.BooleanField, MultiSelectFormField)):
                     continue
                 field.widget.attrs['class'] = 'form-control'
                 
                 field.choices = [(),()]
                 
     # 新增
     def change(request):
         form_obj = Form()
         if request.method =='POST':
             form_obj = Form(request.POST)
             if form_obj.is_valid():  # 对数据做校验的
                 form_obj.save()
                 # 返回展示页面
     
         return render(request,'form.html',{'form_obj':form_obj})
           
         
     
     # 编辑
     def change(request,pk):
         obj = models.XXX.objects.filter(pk=pk).first()
         form_obj = Form(instance=obj)
         if request.method =='POST':
             form_obj = Form(request.POST,instance=obj)
             if form_obj.is_valid():  # 对数据做校验的
                 form_obj.save()
                 # 返回展示页面
     
         return render(request,'form.html',{'form_obj':form_obj})
         
     # form.html
     
     {% for field in form_obj %}
     
      {{ field.label }}  _>  提示
        {{ field.id_for_label }}  _>  input框的id
      {{ field }}  _>  input
        {{ field.errors.0 }}  _>  该字段的第一个错误
         
     {% endfor %}
     
     
     {{ form_obj.as_p }}
     {{ form_obj.errors }}   ——》 所有字段的错误
     {{ form_obj.non_field_errors }}   ——》 __all__的错误
     
     
     

    展示数据

     1. 普通字段
      obj.字段名   ——>  数据库的数据
         
     2. choices参数
      obj.字段名   ——>  数据库的数据
         obj.get_字段名_display()   ——>  要显示的数据
         
     3. 外键
      obj.外键   ——>  外键的对象   __str__
      obj.外键.字段   ——>  外键的对象某个字段的值
         
     4. 自定义的方法
      def show_class(self):
             return  ' , '.join( [  str(i) for i in self.class_list.all() ])
     
         返回HTML字符串,前端加safe 或者 python中加mark_safe
         from django.utils.safestring import mark_safe
     

    删除

    分页

    page = 1

    start = (page-1) * per_num

    end= page * per_num

    data[start:end]

    模糊搜索

    filter(Q(xxx__contains='xxxx')|Q(xxx__contains='xxxx'))

     def search(self,field_list):
         q = Q()
         q.connector = 'OR'
         
         Q(xxx__contains='xxxx')  # Q( ( 'xxx__contains', 'xxxx' ) )
         for field in field_list:
             q.children.append(Q(('{}__contains'.format(field),'xxx')))
     
         return q
         

    分页保留搜索条件

     request.GET  # QueryDict   {'page':'1','query':'xxx'}
     request.GET.urlencode()  # page=1&query=xxx
     qd = request.GET.copy()  # 深拷贝 可编辑
     
     request.GET._mutable=True
     
     qd['page'] = 1
     qd.urlencode()   # ?{}

    编辑后可以跳转到源页面

     1. 生成编辑的地址  地址携带 当前页面的url
     
      "{}?next={}".format(url,request.get_full_path())
      qd = QueryDict(mutable=True)
      qd['next'] = request.get_full_path()
     
      "{}?{}".format(url,qd.urlencode())
     
     
     2. 提交POST请求后跳转到next的地址
      next = requst.GET.get('next')
      retutn redirect(next)
     

    模板中自定义方法 simple_tag

    1. 在app下创建一个名为templatetags的python包

    2. 在包内创建python文件 _> my_tags.py

    3. 在python文件中写固定内容

       form django import template
       register = template.Library()  # register的名字不能错
    4. 写函数 + 加装饰器

       @register.simple_tag
       def reverse_url(request,name,*args,**kwargs):
           qd = QueryDict(mutable=True
        qd['next'] = request.get_full_path()
           url = reverse(name,args=args,kwargs=kwargs)
           
        return "{}?{}".format(url,qd.urlencode())
       
    5. 在模板中使用

       {% load my_tags %}
       
       {% reverse_url request 'edit' pk %}

       

    事务 + 行级锁

    谁先来谁先操作数据

     with transaction.atomic():
                 # 事务
         query_set = models.Customer.objects.filter(pk__in=pks, consultant=None).select_for_update()  # 加锁
     
        if len(pks) == query_set.count():
      query_set.update(consultant=self.request.user_obj)
      else:
             return HttpResponse('你的手速太慢了,需要再练练')

     

    批量初始化学习记录

     models.StudyRecord.objects.bulk_create(study_record_obj_list)

    展示和编辑学习记录 —— modelformset

     from django.forms import modelformset_factory
     
     ModelFormSet = modelformset_factory(models.StudyRecord, StudyRecordForm, extra=0)
     study_records = models.StudyRecord.objects.filter(course_record_id=course_record_id)
     
     formset = ModelFormSet(queryset=study_records)
     
     
     {{ formset.management_form }}
     
     {% for form in formset %}
         <tr>
            {{ form.id }}
             <td>{{ form.instance.student }}</td>
             <td>{{ form.attendance }}</td>
             <td>{{ form.score }}</td>
             <td>{{ form.homework_note }}</td>
             <td class="hidden">{{ form.course_record }}
            {{ form.student }}</td>
         </tr>
     {% endfor %}
     

    权限

    web开发中 url就是权限

    如何实现权限控制?

    RBAC

    一、 表结构

     # 实现权限控制
     
     class Permission(models.Model):
         url = models.CharField(max_length=64,verbose_name='权限') # url地址的正则表达式
         title = models.CharField(max_length=32,verbose_name='标题')
         
     class Role(models.Model):
         name = models.CharField(max_length=32,verbose_name='角色名称')
         permissions = models.ManyToManyField('Permission',blank=True)
         
       
     class User(models.Model):
         username = models.CharField(max_length=32,verbose_name='用户名')
         password = models.CharField(max_length=32,verbose_name='密码')
         roles = models.ManyToManyField('Role',blank=True)
         
     # 动态生成一级菜单
     
     class Permission(models.Model):
         url = models.CharField(max_length=64,verbose_name='权限')
         title = models.CharField(max_length=32,verbose_name='标题')
         is_menu = models.BooleanField(default=False,verbose_name='是否是菜单')
         icon = models.CharField(max_length=32,null=True,blank=True,verbose_name='图标')
         
     class Role(models.Model):
         name = models.CharField(max_length=32,verbose_name='角色名称')
         permissions = models.ManyToManyField('Permission',blank=True)
         
     class User(models.Model):
         username = models.CharField(max_length=32,verbose_name='用户名')
         password = models.CharField(max_length=32,verbose_name='密码')
         roles = models.ManyToManyField('Role',blank=True)
         
         
         
     # 动态生成二级菜单
     class Menu(models.Model):
         title = models.CharField(max_length=32,verbose_name='标题')
         icon = models.CharField(max_length=32,verbose_name='图标')
         weight = models.IntergerField(default=0)
     
     
     class Permission(models.Model):
         """
        menu_id 有menu_id 二级菜单 没有menu_id 普通权限
        """
         url = models.CharField(max_length=64,verbose_name='权限')
         title = models.CharField(max_length=32,verbose_name='标题')
         menu = models.ForeignKey('Menu',null=True,blank=True)
       
         
     class Role(models.Model):
         name = models.CharField(max_length=32,verbose_name='角色名称')
         permissions = models.ManyToManyField('Permission',blank=True)
         
     class User(models.Model):
         username = models.CharField(max_length=32,verbose_name='用户名')
         password = models.CharField(max_length=32,verbose_name='密码')
         roles = models.ManyToManyField('Role',blank=True)

    二、 登录成功后 查询当前用户的权限信息 并保存到session中

     #  简单的控制
     
     permissions = obj.roles.exclude(permissions__url=None).values('permissions__url').distinct()
     # QuerySet<[ {'permissions__url':'xxxx'} ]>
     
     request.session['permissions'] = list(permissions)
     
     
     # 动态生成一级菜单
     
     permissions = obj.roles.exclude(permissions__url=None).values(
         'permissions__url',
         'permissions__is_menu',
         'permissions__title',
         'permissions__icon',
     ).distinct()
     # QuerySet<[ {'permissions__url':'xxxx'} ]>
     
     # 权限列表
     permission_list = [ { 'url': i['permissions__url'] } ]
     # 菜单的列表
     menu_list = [
        { 'url'  'title'  'icon'}
     ]
     
     
     request.session['permissions'] = permission_list
     request.session['menus'] = menu_list
     
     
     # 动态生成二级菜单
     
     permissions = obj.roles.exclude(permissions__url=None).values(
         'permissions__url',
         'permissions__title',
         'permissions__menu__title',
         'permissions__menu__icon',
         'permissions__menu__weight',
         'permissions__menu_id',
     ).distinct()
     # QuerySet<[ {'permissions__url':'xxxx'} ]>
     
     # 权限列表
     permission_list = [ { 'url': i['permissions__url'] } ]
     
     # 菜单的列表
     menu_dict = {
         
         一级菜单的id : {
             'title':'一级菜单的标题'
             'icon':'一级菜单的图标'
             'weight':'一级菜单的权重'
             'children': [
                { 'url'   'title' }
                 
            ]
        }
         
     }
     
     
     request.session['permissions'] = permission_list
     request.session['menus'] = menu_dict
     
     

    三、 每次请求 都做权限的校验

    中间件 process_request

     from djang.conf import settings
     
     # 获取了当前的url地址
     url = request.path_info
     
     # 白名单
     for i in  settings.WHITE_LIST :
         if re.match(i,url):
             return
     
     # 登录状态的校验
     is_login = request.session.get('is_login')
     if not is_login:
         return redirect('login')
     
     
     # 免认证地址的校验
     for i in  settings.NO_PERMISSION_LIST :
         if re.match(i,url):
             return
     
     # 获取权限信息
     permissions = request.session.get('permissions')
     for i in permissions :  # {'permissions__url':'xxxx'}
         if re.match(r"^{}$".format(i['url']),url):
             return
     
         
     return HttpResponse('没有权限')

    动态生成一级菜单

     #  menu.html
     
     <div class="static-menu">
     
        {% for menu in menu_list %}
             <a href="{{ menu.url }}"  class="{{ menu.class }}" >
                 <span class="icon-wrap"><i class="fa {{ menu.icon }}"></i></span> {{ menu.title }}</a>
        {% endfor %}
     
     </div>
     
     

    使用inclusion_tag 实现菜单

     @register.inclusion_tag('rbac/menu.html')
     def menu(request):
         url = request.path_info
     
         menu_list = request.session.get(settings.MENU_SESSION_KEY)
         # [ {'url' class } {'url' }{'url' }]
         for i in menu_list:
             if re.match(r'^{}$'.format(i['url']), url):
                 i['class'] = 'active'
                 break
     
         return {'menu_list': menu_list}

    在模板中使用:

     
     {% load rbac %}
     {% menu request %}
     

    动态生成二级菜单

     #  menu2.html
     
     <div class="multi-menu">
     
     
        {% for menu in menu_list %}
     
             <div class="item">
                 <div class="title"><i class="fa {{ menu.icon }}"></i> {{ menu.title }}</div>
                 <div class="body {{ menu.class }}">
     
                    {% for child in menu.children %}
                         <a class="{{ child.class }}" href="{{ child.url }}">{{ child.title }}</a>
                    {% endfor %}
     
                 </div>
     
             </div>
     
        {% endfor %}
     
     </div>
     
     

    使用inclusion_tag 实现菜单

     @register.inclusion_tag('rbac/menu.html')
     def menu(request):
         url = request.path_info
     
         menu_dict = request.session.get(settings.MENU_SESSION_KEY)
     
         menu_list = []
         
         for i in sorted(menu_dict,key=lambda x:menu_dict[x]['weight'],reverse=True):
        menu_list.append(menu_dict[i])
             
         for item in menu_list:
     
             item['class'] = 'hidden'
     
             for i in item['children']:
                 if re.match(r'^{}$'.format(i['url']), url):
                     i['class'] = 'active'
                     item['class'] = ''
                     break
     
         return {'menu_list':menu_list }

    在模板中使用:

     {% load  rbac %}
     {% menu request %}
     

    非菜单的权限的归属的问题

    id url title menu_id parent_id

    1 list 客户列表 1 null 2 add 添加客户 null 1 3 edit 编辑客户 null 1 4 del 删除客户 null 1

    自定义filter

  • 相关阅读:
    eclipse中包的位置
    404代码错误解决
    servlet-web.xml配置
    java web.xml配置servlet
    1031整理
    1030整理
    rownum
    存储过程和自定义函数的区别
    课堂整理
    练习
  • 原文地址:https://www.cnblogs.com/zhang-da/p/12195292.html
Copyright © 2011-2022 走看看