day27-crm业务

'''
一.为用户表增加字段,继承rbac的信息,注意role去掉引号(因为crm中的models中无role的类,rbac中有)
rbac的models中
class AbstractUserInfo(models.Model):
    """
    用户表
    """
    username = models.CharField(verbose_name='用户名', max_length=32)
    password = models.CharField(verbose_name='密码', max_length=64)
    roles = models.ManyToManyField(verbose_name='关联角色', to=Role)
    
    class Meta:
        abstract = True  # 表示让django的orm不再为该类在数据库创建表


crm的models中:

class UserInfo(AbstractUserInfo):
    """
    用户表
    """
    gender_choice = (
        (1, ""),
        (2, ""),
    )
    gender = models.IntegerField(verbose_name="性别", choices=gender_choice, default=1)  # 注意添加gender字段,否则数据库中无表结构改变
    depart = models.ForeignKey(verbose_name='部门', to='Department')

    email = models.EmailField(verbose_name='邮箱', null=True, blank=True)
    phone = models.CharField(verbose_name='手机', max_length=32, null=True, blank=True)

    def __str__(self):
        return self.username
用户表

复习部门的增删改操作
二.用户的增删改查操作

用户增删改1.展示角色??--多对多字段展示方法
user_list中
<td>{% for role in row.roles.all %}
<span style="display: inline-block;padding:5px;border: 1px solid#dddddd;">
{{ role.title }}
</span>

{% endfor %}
</td>

2.编辑中部门显示名称?
crm的models中
def __str__(self):
return self.title

普通字段、m2m、fk、choice展示方法
{% extends 'layout.html' %}
{% load rbac %}

{% block content %}
    <h1>用户列表</h1>
    {% if 'user_add'|permission:request %}
        <a class="btn btn-primary" href="{% url 'user_add' %}">添加</a>
    {% endif %}
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>ID</th>
            <th>用户名</th>
            <th>性别</th>

            <th>密码</th>
            <th>邮箱</th>
            <th>电话</th>
            <th>所属部门</th>
            <th>角色</th>
            {% if "user_edit"|permission:request or "user_del"|permission:request %}
                <th>操作</th>
            {% endif %}
        </tr>
        </thead>
        <tbody>
        {% for row in queryset %}
            <tr>
                <td>{{ row.id }}</td>
                <td>{{ row.username }}</td>
                <td>{{ row.get_gender_display }}</td>

                <td>{{ row.password }}</td>
                <td>{{ row.email }}</td>
                <td>{{ row.phone }}</td>
                <td>{{ row.depart.title }}</td>
                {#                <td>{{ row.roles.all }}</td>#}
                <td>{% for role in row.roles.all %}
                    <span style="display: inline-block;padding:5px;border: 1px solid#dddddd;">
                    {{ role.title }}
                    </span>

                {% endfor %}
                </td>

                {% if "user_edit"|permission:request or "user_del"|permission:request %}
                    <td>
                        {% if "user_edit"|permission:request %}
                            <a href="{% url 'user_edit' row.id %}">编辑</a>
                        {% endif %}

                        {% if "user_del"|permission:request %}
                            <a href="{% url 'user_del' row.id %}">删除</a>
                        {% endif %}
                    </td>
                {% endif %}
            </tr>
        {% endfor %}
        </tbody>
    </table>


{% endblock %}
user_list.html

user_add.html 中(所有的都是) field.label 表示 取得每个字段名字的verbose_name

'''


'''
3.对密码进行加密的处理---写在forms的钩子函数中
md5不能反解,可以进行撞库----需要加盐
forms的 class UserinfoForm(ModelForm):类中
def clean_password(self):
"""
密码对应的钩子方法
:return:
"""
user_input_pwd = self.cleaned_data['password']
return md5(user_input_pwd)

md5.py中
def md5(data):
"""
MD5加密
:param data: 要加密的字符串
:return: 加密后的字符串
"""
hash = hashlib.md5(b'lijie')
hash.update(data.encode('utf-8'))
return hash.hexdigest()

'''

'''
related_name 通过制定的字段进行反向关联
三.看老师书写课程、学校、班级的增删改查
---拼接一个班级名称 {{ row.course.name }}{{ row.semester }}期

四、客户表------------------从这开始看即可!!!开始写!!
--有些字段可以为空
--公户私户管理----课程顾问为空则为公户--17个字段customer表,展示15个,两个日期未展示???
exclude排除不展示
批量操作-加一个checkbox列,--变成我的客户
把当前用户放到session,然后获取即可!
from django.shortcuts import render, redirect
from crm import models
from rbac import models as rbac_model
from rbac.service.permission import init_permission
from crm.forms.public import PublicForm


def public_customer_list(request):
    """
    公户列表
    :param request:
    :return:
    """
    if request.method == 'POST':
        id_list = request.POST.getlist('pk')
        current_user_id = request.session['user_info']['id'] #user_info是啥??
        models.Customer.objects.filter(id__in=id_list).update(consultant_id=current_user_id)#如果id在pk列表中,更新课程顾问的id为当前用户的id

    queryset = models.Customer.objects.filter(consultant__isnull=True) #表示consultant可以为空
    return render(request, 'public_customer_list.html', {'queryset': queryset})



def public_customer_add(request):
    if request.method == 'GET':
        form = PublicForm()
        return render(request, 'forms.html', {'form': form})
    form = PublicForm(data=request.POST)
    if form.is_valid():
        form.save()
        return redirect('/public/customer/list/')
    return render(request, 'forms.html', {'form': form})


def public_customer_edit(request, nid):
    """
    编辑
    :param request:
    :return:
    """
    # obj = models.Department.objects.get(id=nid)
    obj = models.Customer.objects.filter(id=nid).first()
    if request.method == 'GET':
        form = PublicForm(instance=obj)
        return render(request, 'forms.html', {'form': form})
    form = PublicForm(data=request.POST, instance=obj)  # 注意instance,否则是新增一个
    if form.is_valid():
        form.save()
        return redirect('/public/customer/list/')
    return render(request, 'forms.html', {'form': form})


def public_customer_del(request, nid):
    """
    删除
    :param request:
    :return:
    """
    models.Customer.objects.filter(id=nid).delete()
    return redirect('/public/customer/list/')
公户列表views
{% extends 'layout.html' %}
{% load rbac %}

{% block content %}
    <h1>客户列表</h1>
    <form method="post">
    {% csrf_token %}
        <div>
           {% if 'public_customer_add'|permission:request %}
                <a class="btn btn-primary" href="{% url 'public_customer_add' %}">添加</a>
            {% endif %}
            <input type="submit" value="申请到我的私户" class="btn btn-primary">
        </div>
        <table class="table table-bordered">
            <thead>
            <tr>
                <th>选择</th>
                <th>姓名</th>
                <th>联系方式</th>
                <th>状态</th>
                <th>性别</th>
                <th>是否转介绍</th>
                <th>咨询课程</th>
    {#            <th>课程顾问</th>#}
                <th>咨询日期</th>
                {% if "public_customer_edit"|permission:request or "public_customer_del"|permission:request %}
                    <th>操作</th>
                {% endif %}
            </tr>
            </thead>
            <tbody>
            {% for row in queryset %}
                <tr>
                    <td><input name='pk' type="checkbox" value="{{ row.id }}"></td>
                    <td>{{ row.name }}</td>
                    <td>{{ row.qq }}</td>
                    <td>{{ row.get_status_display }}</td>
                    <td>{{ row.get_gender_display }}</td>
                    <td>{{ row.referral_from.name }}</td>
                    <td>{% for ele in row.courses.all %}
                        <span style="display: inline-block;padding:5px;border: 1px solid#dddddd;">
                        {{ ele.name }}
                        </span>
                    {% endfor %}
                    </td>
    {#                <td>{{ row.consultant.username }}</td>#}
                    <td>{{ row.date }}</td>
                    {% if "public_customer_edit"|permission:request or "public_customer_del"|permission:request %}
                        <td>
                            {% if "public_customer_edit"|permission:request %}
                                <a href="{% url 'public_customer_edit' row.id %}">编辑</a>
                            {% endif %}
                            {% if "public_customer_del"|permission:request %}
                                <a href="{% url 'public_customer_del' row.id %}/">删除</a>
                            {% endif %}
                        </td>
                    {% endif %}
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </form>
{% endblock %}
公户列表html
from django.forms import ModelForm, Form
from crm import models


class PrivateForm(ModelForm):
    class Meta:
        model = models.Customer
        # fields = "__all__"
        exclude = ['consultant',]  #排除课程顾问字段不展示




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

        for title, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = field.label
公户列表forms(同私户)
from django.shortcuts import render, redirect
from crm import models
from rbac import models as rbac_model
from rbac.service.permission import init_permission
from crm.forms.private import PrivateForm


def private_customer_list(request):
    """
    私户列表
    :param request:
    :return:
    """
    if request.method == 'POST':
        id_list = request.POST.getlist('pk')

        models.Customer.objects.filter(id__in=id_list).update(consultant=None)#如果id在pk列表中,更新课程顾问为空

    current_user_id = request.session['user_info']['id'] #注意在if外面
    queryset = models.Customer.objects.filter(consultant_id=current_user_id).order_by('-status') #表示按状态列表中倒序(按照报名状态排序,未报名在上面,负号表示倒序)
    return render(request, 'private_customer_list.html', {'queryset': queryset})



def private_customer_add(request):
    """
       录入私户信息
       :param request:
       :return:
       """
    if request.method == 'GET':
        form = PrivateForm()
        return render(request, 'forms.html', {'form': form})
    form = PrivateForm(data=request.POST)
    if form.is_valid():
        # 课程顾设置成我自己
        form.instance.consultant_id = request.session['user_info']['id']
        # form.instance.consultant = models.UserInfo.objects.get(id=request.session['user_info']['id']) 又做了一个查询,效率低
        form.save()
        return redirect('/private/customer/list/')
    return render(request, 'forms.html', {'form': form})


def private_customer_edit(request, nid):
    """
    编辑
    :param request:
    :return:
    """
    # obj = models.Department.objects.get(id=nid)
    obj = models.Customer.objects.filter(id=nid).first()
    if request.method == 'GET':
        form = PrivateForm(instance=obj)
        return render(request, 'forms.html', {'form': form})
    form = PrivateForm(data=request.POST, instance=obj)  # 注意instance,否则是新增一个
    if form.is_valid():
        form.save()
        return redirect('/private/customer/list/')
    return render(request, 'forms.html', {'form': form})
私户列表views
{% extends 'layout.html' %}
{% load rbac %}

{% block content %}
    <h1>客户列表</h1>
    <form method="post">
        {% csrf_token %}
        <div>
            {% if 'private_customer_add'|permission:request %}
                <a class="btn btn-primary" href="{% url 'private_customer_add' %}">添加</a>
            {% endif %}
            <input type="submit" value="踢出到公户" class="btn btn-primary">
        </div>
        <table class="table table-bordered">
            <thead>
            <tr>
                <th>选择</th>
                <th>姓名</th>
                <th>联系方式</th>
                <th>状态</th>
                <th>性别</th>
                <th>是否转介绍</th>
                <th>咨询课程</th>
                {#            <th>课程顾问</th>#}
                <th>咨询日期</th>
                <th>跟进</th>
                {% if "private_customer_edit"|permission:request %}
                    <th>操作</th>
                {% endif %}
            </tr>
            </thead>
            <tbody>
            {% for row in queryset %}
                <tr>
                    <td><input name='pk' type="checkbox" value="{{ row.id }}"></td>
                    <td>{{ row.name }}</td>
                    <td>{{ row.qq }}</td>
                    <td>{{ row.get_status_display }}</td>
                    <td>{{ row.get_gender_display }}</td>
                    <td>{{ row.referral_from.name }}</td>
                    <td>{% for ele in row.courses.all %}
                        <span style="display: inline-block;padding:5px;border: 1px solid#dddddd;">
                        {{ ele.name }}
                        </span>
                    {% endfor %}
                    </td>
                    {#                <td>{{ row.consultant.username }}</td>#}
                    <td>{{ row.date }}</td>
                 <td>
                        <a href="{% url 'record_list' row.id %}">跟进</a>
                    </td>
                    <td>
                      {% if "private_customer_edit"|permission:request %}
                            <a href="{% url 'private_customer_edit'  row.id %}">编辑</a>
                        {% endif %}

                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </form>
{% endblock %}
私户列表html

五、用户登录
用户登录中间件--用户登录白名单
#用户登录,信息保存到session中
from django.shortcuts import redirect,render
from django.urls import reverse
from crm import models
from crm.utils.md5 import md5
from rbac.service.permission import init_permission

from django.contrib import auth

def login(request):
    if request.method == 'GET':
        return  render(request,'login.html')

    user = request.POST.get('username')
    pwd = md5(request.POST.get('password'))
    user_obj = models.UserInfo.objects.filter(username=user,password=pwd).first()

    if not user_obj:
        return render(request,'login.html',{'error':'用户名或密码错误'}) # 获取用户名、密码在login.html中注意是post请求

    request.session['user_info'] = {'id':user_obj.id,'name':user_obj.username}

    init_permission(user_obj,request)
    # return redirect(reverse('public_customer_list'))
    # return redirect('/public/customer/list/')
    # next = request.path_info
    # return redirect("/login/?next={}".format(next))  # --------问题2.跳转到next=login界面了!!
    return redirect(reverse('index'))

def index(request): #index页面展示报错!!'WSGIRequest' object has no attribute 'default_selected_menu_name'
    return render(request,'index.html')


def logout(request):
    auth.logout(request)  # request.session.flush()
    return redirect("/login/")
用户登录视图(login/index/logout)
import re
from django.utils.deprecation import MiddlewareMixin
'''
在settings中复制第47行,加上from,最后的.改为import
选择CommonMiddleware,鼠标左键加ctrl,找到MiddlewareMixin,复制
导入它的import即可
from django.middleware.common import CommonMiddleware
from django.utils.deprecation import MiddlewareMixin
'''

from django.shortcuts import redirect
from django.conf import settings

class AuthMiddleware(MiddlewareMixin):
    def process_request(self,request):
        """
        检查用户登陆的中间件
        :param request:
        :return:
        """
        for url in settings.AUTH_VALID_URL:
            if re.match(url,request.path_info):
                return None

        user_info = request.session.get('user_info')
        if not user_info:
            return redirect('/login/')
检查用户登陆的中间件
# #################### 用户登录配置 #######################
# 不用登录就可以访问的页面
AUTH_VALID_URL = [
    '/login/',
    '/admin.*',
]
settings中配置

六、私户列表
1.按照报名状态排序,未报名在上面,负号表示倒序;
2.无法删除公司用户
3.私户添加应该增加到自己的页面,save之前设置一个值(课程顾客是我自己
form.instance.consultant_id = request.session['user_info']['id']),在models中不写
4.移至公户功能
七、跟进表--要限制只能查看自己的用户,拿到客户id和客户;
增加在save之前,插入时增加instance两项
跟进记录不能删除和修改
from django.forms import ModelForm, Form
from crm import models


class RecordForm(ModelForm):
    class Meta:
        model = models.ConsultRecord
        # fields = "__all__"
        fields = ['note',]



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

        for title, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = field.label
跟进表record的forms
from django.shortcuts import render, redirect,HttpResponse
from django.urls import reverse
from crm import models
from rbac import models as rbac_model
from rbac.service.permission import init_permission
from crm.forms.record import RecordForm


def record_list(request,nid):
    """
     跟进记录
    :param nid: 客户ID
    :param request:
    :return:
    """
    current_user_id = request.session['user_info']['id']

    exists = models.Customer.objects.filter(id=nid, consultant_id=current_user_id).exists()
    if not exists:
        return HttpResponse('只能查看自己客户的跟进记录')
    queryset = models.ConsultRecord.objects.filter(customer_id=nid) #注意是customer_id,只写id添加完不显示在列表中!
    return render(request, 'record_list.html', {'queryset': queryset,'cid':nid})


def record_add(request,cid):
    """
      :param request:
      :param cid: 客户ID
      :return:
    """
    if request.method == 'GET':
        form = RecordForm()
        return render(request, 'forms.html', {'form': form})
    form = RecordForm(data=request.POST)
    if form.is_valid():

        form.instance.customer_id = cid
        form.instance.consultant_id = request.session['user_info']['id']

        form.save()
        # return redirect('/record/list/',args=(cid,))
        return redirect(reverse('record_list', args=(cid,))) #注意携带cid
    return render(request, 'forms.html', {'form': form})
跟进表的views
{% extends 'layout.html' %}
{% load rbac %}

{% block content %}
    <h1>跟进记录</h1>
    <div>
        {% if 'record_add'|permission:request %}
            <a class="btn btn-primary" href="{% url 'record_add' cid %}">添加</a>
        {% endif %}
    </div>
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>内容</th>
            <th>顾问</th>
{#            <th>跟进日期</th>#}
        </tr>
        </thead>
        <tbody>
        {% for row in queryset %}
            <tr>
                <td>{{ row.note }}</td>
                <td>{{ row.consultant.username }}</td>
{#                <td>{{ row.date }}</td>#}
            </tr>
        {% endfor %}
        </tbody>
    </table>
{% endblock %}
跟进表的html

八、权限的应用---重点--readme中9步
目标:将rbac做成一个公共组件,组件包含:权限控制、菜单的定制、页面定制。

使用步骤:
    1. 拷贝rbac应用

    2. 删除rbac/migrations目录中除 __init__.py 以外的所有文件

    3. 配置文件中注册 rbac的app
        INSTALLED_APPS = [
            ...
            'rbac.apps.RbacConfig',
        ]

    4. 数据库迁移
        python manage.py makemigrations
        python manage.py migrate


    5. 编写测试系统的业务逻辑
        如果使用rbac中的模板的话,需要先删除layout.html中的:
             <!-- 导入xxxxxxx模块 -->
            {% load rbac %}
            <!-- 执行get_menu函数并传递了一个参数 -->
            {% get_menu request %}

        业务逻辑开发完毕....

    6. 设置权限相关的配置文件
        # ############################ 权限+菜单相关配置 #############################
        RBAC_PERMISSION_SESSION_KEY = "ijksdufwesdfs"
        RBAC_MENU_SESSION_KEY = "rtwsdfgwerffsd"

        VALID_LIST = [
            '/api/login/',
            '/admin/.*'
        ]

    7. 基于django admin 录入权限数据
        - 菜单
        - 权限
        - 权限角色关系表
        - 角色
        - 用户角色关系表
        - 用户

    8. 权限和菜单信息的应用
        - 用户登录:初始化权限和菜单信息
            def login(request):
                """
                用户登录
                :param request:
                :return:
                """
                if request.method == "GET":
                    return render(request, 'api/login.html')

                user = request.POST.get('user')
                pwd = request.POST.get('pwd')

                user = rbac_model.UserInfo.objects.filter(username=user, password=pwd).first()
                if not user:
                    return render(request, 'api/login.html', {'msg': '用户名或密码错误'})
                # ############ 看这里 ############
                init_permission(user, request)

                return redirect('/api/app/list/')
        - 中间件:权限判断
            settings.py
                MIDDLEWARE = [
                    ...
                    'rbac.middlewares.rbac.RBACMiddleware',
                ]
        - inclusion_tag:动态生成菜单
            layout.html
                <div class="menu-body">
                    {% load rbac %}

                    {% get_menu request %}
                </div>


    9. 控制页面按钮

        {% extends 'layout.html' %}

        {% load rbac %}

        {% block content %}
            <h1>应用列表</h1>

            {% if 'app_add'|permission:request %}
                <a class="btn btn-primary" href="{% url 'app_add' %}">添加</a>
            {% endif %}

            <table class="table table-bordered">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>姓名</th>
                         {% if "app_edit"|permission:request or "app_del"|permission:request %}
                        <th>操作</th>
                        {% endif %}
                    </tr>
                </thead>
                <tbody>
                    {% for row in app_queryset %}
                        <tr>
                            <td>{{ row.id }}</td>
                            <td>{{ row.title }}</td>
                            {% if "app_edit"|permission:request or "app_del"|permission:request %}
                            <td>
                                {% if "app_edit"|permission:request %}
                                    <a href="{% url 'app_edit' row.id %}">编辑</a>
                                {% endif %}
                                {% if "app_del"|permission:request %}
                                    <a href="{% url 'app_del' row.id %}/">删除</a>
                                {% endif %}
                            </td>
                            {% endif %}
                        </tr>
                    {% endfor %}
                </tbody>
            </table>


        {% endblock %}
nb的readme
1.分配权限
2.左侧动态菜单的生成
3.粒度控制到按钮
-----------把欢迎登录放入白名单就完美了!
# 问题1.。index页面展示报错!!'WSGIRequest' object has no attribute 'default_selected_menu_name'
#在middlewares的rbac中 添加request.default_selected_menu_name = None 即可解决!

参考最后项目
注:
# 注1:首次使用http://127.0.0.1:8000/permission/list/添加菜单、权限和角色时,把权限判断的中间件注释掉(# 'rbac.middlewares.rbac.RBACMiddleware',)否则提示无权访问
# 注2:roles相关页面展示报错!!'WSGIRequest' object has no attribute 'default_selected_menu_name',
需注释{# {% get_menu request %}#}及{% if 'roles_add'|permission:request %}#}{% endif %}#}
"""s21crm URL Configuration
"""
from django.conf.urls import url
from django.contrib import admin
from crm.views import account

from crm.views import depart
from crm.views import user
from crm.views import course
from crm.views import school
from crm.views import classes
from crm.views import public
from crm.views import private
from crm.views import record
# 权限表的相关业务
from rbac.views import menu
from rbac.views import roles
from rbac.views import permission

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', account.login, name='login'),
    url(r'^index/', account.index, name='index'),
    # 问题1.index页面展示报错!!'WSGIRequest' object has no attribute 'default_selected_menu_name'
#在middlewares的rbac中 添加request.default_selected_menu_name = None 即可解决!
    # 部门#----------
    url(r'^depart/list/', depart.depart_list, name='depart_list'),
    url(r'^depart/add/', depart.depart_add, name='depart_add'),
    url(r'^depart/edit/(\d+)/$', depart.depart_edit, name='depart_edit'),
    url(r'^depart/del/(\d+)$', depart.depart_del, name='depart_del'),
    # 用户-----------
    url(r'^user/list/', user.user_list, name='user_list'),
    url(r'^user/add/', user.user_add, name='user_add'),
    url(r'^user/edit/(\d+)/$', user.user_edit, name='user_edit'),
    url(r'^user/del/(\d+)/$', user.user_del, name='user_del'),
    # 课程-course-------------
    url(r'^course/list/', course.course_list, name='course_list'),
    url(r'^course/add/', course.course_add, name='course_add'),
    url(r'^course/edit/(\d+)/$', course.course_edit, name='course_edit'),
    url(r'^course/del/(\d+)/$', course.course_del, name='course_del'),

    # 学校---school----------------
    url(r'^school/list/', school.school_list, name='school_list'),
    url(r'^school/add/', school.school_add, name='school_add'),
    url(r'^school/edit/(\d+)$', school.school_edit, name='school_edit'),
    url(r'^school/del/(\d+)$', school.school_del, name='school_del'),
    #  班级---classes----------------
    url(r'^classes/list/', classes.classes_list, name='classes_list'),
    url(r'^classes/add/', classes.classes_add, name='classes_add'),
    url(r'^classes/edit/(\d+)/$', classes.classes_edit, name='classes_edit'),
    url(r'^classes/del/(\d+)/$', classes.classes_del, name='classes_del'),

    # 客户---customer---- 公户public -----
    url(r'^public/customer/list/', public.public_customer_list, name='public_customer_list'),
    url(r'^public/customer/add/', public.public_customer_add, name='public_customer_add'),
    url(r'^public/customer/edit/(\d+)/$', public.public_customer_edit, name='public_customer_edit'),
    url(r'^public/customer/del/(\d+)/$', public.public_customer_del, name='public_customer_del'),

    # ---私户  private---无删除功能-
    url(r'^private/customer/list/', private.private_customer_list, name='private_customer_list'),
    url(r'^private/customer/add/', private.private_customer_add, name='private_customer_add'),
    url(r'^private/customer/edit/(\d+)/$', private.private_customer_edit, name='private_customer_edit'),

    # 客户跟进记录--record---------跟进记录不能删除和修改-----
    url(r'^record/list/(\d+)/$', record.record_list, name='record_list'),
    url(r'^record/add/(\d+)/$', record.record_add, name='record_add'),  # \d+为客户id

    # 菜单-------menu---左侧是动态生成,但菜单也可以增删改操作---------------
    url(r'^menu/list/', menu.menu_list, name='menu_list'),
    url(r'^menu/add/', menu.menu_add, name='menu_add'),
    url(r'^menu/edit/(\d+)/$', menu.menu_edit, name='menu_edit'),
    url(r'^menu/del/(\d+)/$', menu.menu_del, name='menu_del'),

    # 注1:首次使用http://127.0.0.1:8000/permission/list/添加菜单、权限和角色时,把权限判断的中间件注释掉(    # 'rbac.middlewares.rbac.RBACMiddleware',)否则提示无权访问
    # 注2:roles相关页面展示报错!!'WSGIRequest' object has no attribute 'default_selected_menu_name',需注释{#            {% get_menu request %}#}及{% if 'roles_add'|permission:request %}#}{% endif %}#}
    # 角色--------roles----------------------
    url(r'^roles/list/', roles.roles_list, name='roles_list'),
    url(r'^roles/add/', roles.roles_add, name='roles_add'),
    url(r'^roles/edit/(\d+)/$', roles.roles_edit, name='roles_edit'),
    url(r'^roles/del/(\d+)/$', roles.roles_del, name='roles_del'),

    # 权限--------permissions---------------------------------
    url(r'^permission/list/', permission.permission_list, name='permission_list'),
    url(r'^permission/add/', permission.permission_add, name='permission_add'),
    url(r'^permission/edit/(\d+)/$', permission.permission_edit, name='permission_edit'),
    url(r'^permission/del/(\d+)/$', permission.permission_del, name='permission_del'),

    # 其它功能--注销
    url(r'^logout/', account.logout, name='logout'),

]
所有的urls
"""
Django settings for s21crm project.

Generated by 'django-admin startproject' using Django 1.11.11.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'ecx-vni_bajq)%4w8ep*gxr1qdz6i7*qo0tdqb-9+zy$2$pra5'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crm.apps.CrmConfig',
    'rbac.apps.RbacConfig'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'crm.middlewares.auth.AuthMiddleware',  # 注意应用用户登录中间件
    'rbac.middlewares.rbac.RBACMiddleware', #权限中间件
]

ROOT_URLCONF = 's21crm.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 's21crm.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

# #################### 用户登录配置 #######################
# 不用登录就可以访问的页面
AUTH_VALID_URL = [
    '/login/',
    '/admin.*',
]

# ############################ 权限+菜单相关配置 #############################
RBAC_PERMISSION_SESSION_KEY = "ijksdufwesdfs"
RBAC_MENU_SESSION_KEY = "rtwsdfgwerffsd"

VALID_LIST = [
    '/login/',
    '/logout/',
    '/index/',
    '/admin/.*'
]
settings
from django.db import models


class Menu(models.Model):
    """
    菜单表
    """
    title = models.CharField(verbose_name='标题', max_length=32)
    icon = models.CharField(verbose_name='图标', max_length=32)
    
    def __str__(self):
        return self.title


class Permission(models.Model):
    """
    权限表
    """
    url = models.CharField(verbose_name='URL(含正则)', max_length=128)
    title = models.CharField(verbose_name='名称', max_length=32)
    name = models.CharField(verbose_name='别名', max_length=32, unique=True)
    
    menu = models.ForeignKey(verbose_name='管理菜单', to='Menu', to_field='id', null=True, blank=True)
    parent = models.ForeignKey(verbose_name='父菜单', to='Permission', null=True, blank=True)
    
    def __str__(self):
        return self.title


class Role(models.Model):
    """
    角色表
    """
    title = models.CharField(verbose_name='名称', max_length=32)
    permissions = models.ManyToManyField(verbose_name='关联权限', to='Permission')
    
    def __str__(self):
        return self.title


class AbstractUserInfo(models.Model):
    """
    用户表
    """
    username = models.CharField(verbose_name='用户名', max_length=32)
    password = models.CharField(verbose_name='密码', max_length=64)
    roles = models.ManyToManyField(verbose_name='关联角色', to=Role)
    
    class Meta:
        abstract = True  # 表示让django的orm不再为该类在数据库创建表
rbac中models--重点
from django.db import models
from rbac.models import AbstractUserInfo


class Department(models.Model):
    """
    部门表
    """
    title = models.CharField(verbose_name='部门', max_length=32)

    def __str__(self):  # 表中内容显示中文,而不是object对象
        return self.title

    class Meta:  # admin登录页面显示中文
        verbose_name = "部门表"
        verbose_name_plural = verbose_name


class UserInfo(AbstractUserInfo):
    """
    用户表
    """
    gender_choice = (
        (1, ""),
        (2, ""),
    )
    gender = models.IntegerField(verbose_name="性别", choices=gender_choice, default=1)  # 注意添加gender字段,否则数据库中无表结构改变
    depart = models.ForeignKey(verbose_name='部门', to='Department')

    email = models.EmailField(verbose_name='邮箱', null=True, blank=True)
    phone = models.CharField(verbose_name='手机', max_length=32, null=True, blank=True)

    def __str__(self):
        return self.username


class Course(models.Model):
    """
    课程表
    如:
        Linux基础
        Linux架构师
        Python自动化
        Python全栈
    """
    name = models.CharField(verbose_name='课程名称', max_length=32)

    def __str__(self):
        return self.name


class School(models.Model):
    """
    校区表
    如:
        北京昌平校区
        上海浦东校区
        深圳南山校区
    """
    title = models.CharField(verbose_name='校区名称', max_length=32)

    def __str__(self):
        return self.title


class ClassList(models.Model):
    """
    班级表
    如:
        Python全栈  面授班  5期  10000  2017-11-11  2018-5-11
    """
    school = models.ForeignKey(verbose_name='校区', to='School')
    course = models.ForeignKey(verbose_name='课程名称', to='Course')
    semester = models.IntegerField(verbose_name="班级(期)")  # 11
    price = models.IntegerField(verbose_name="学费")
    start_date = models.DateField(verbose_name="开班日期", null=True, blank=True)
    graduate_date = models.DateField(verbose_name="结业日期", null=True, blank=True)

    # related_name用于orm的反向查找,替代 classlist_set
    tutor = models.ForeignKey(verbose_name='班主任', to='UserInfo', related_name='classes')
    teachers = models.ManyToManyField(verbose_name='任课老师', to='UserInfo', related_name='teach_classes')

    memo = models.CharField(verbose_name='说明', max_length=255, blank=True, null=True)

    def __str__(self):
        return "{0}({1}期)".format(self.course.name, self.semester)


class Customer(models.Model):
    """
    客户表
    """
    name = models.CharField(verbose_name='姓名', max_length=32)
    qq = models.CharField(verbose_name='联系方式', max_length=64, unique=True, help_text='QQ号/微信/手机号')

    status_choices = [
        (1, "已报名"),
        (2, "未报名")
    ]
    status = models.IntegerField(verbose_name="状态", choices=status_choices, default=2)

    gender_choices = (
        (1, ''),
        (2, '')
    )
    gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)

    source_choices = [
        (1, "qq群"),
        (2, "内部转介绍"),
        (3, "官方网站"),
        (4, "百度推广"),
        (5, "360推广"),
        (6, "搜狗推广"),
        (7, "腾讯课堂"),
        (8, "广点通"),
        (9, "高校宣讲"),
        (10, "渠道代理"),
        (11, "51cto"),
        (12, "智汇推"),
        (13, "网盟"),
        (14, "DSP"),
        (15, "SEO"),
        (16, "其它"),
    ]
    source = models.SmallIntegerField('客户来源', choices=source_choices, default=1)

    referral_from = models.ForeignKey(
        'self',
        blank=True,
        null=True,
        verbose_name="转介绍自学员",
        help_text="若此客户是转介绍自内部学员,请在此处选择内部学员姓名",
        related_name="internal_referral"
    )

    courses = models.ManyToManyField(verbose_name="咨询课程", to="Course")

    consultant = models.ForeignKey(verbose_name="课程顾问", to='UserInfo', related_name='consultant', null=True,
                                   blank=True)

    education_choices = (
        (1, '重点大学'),
        (2, '普通本科'),
        (3, '独立院校'),
        (4, '民办本科'),
        (5, '大专'),
        (6, '民办专科'),
        (7, '高中'),
        (8, '其他')
    )
    education = models.IntegerField(verbose_name='学历', choices=education_choices, blank=True, null=True, )

    graduation_school = models.CharField(verbose_name='毕业学校', max_length=64, blank=True, null=True)
    major = models.CharField(verbose_name='所学专业', max_length=64, blank=True, null=True)

    experience_choices = [
        (1, '在校生'),
        (2, '应届毕业'),
        (3, '半年以内'),
        (4, '半年至一年'),
        (5, '一年至三年'),
        (6, '三年至五年'),
        (7, '五年以上'),
    ]
    experience = models.IntegerField(verbose_name='工作经验', blank=True, null=True, choices=experience_choices)
    work_status_choices = [
        (1, '在职'),
        (2, '无业')
    ]
    work_status = models.IntegerField(verbose_name="职业状态", choices=work_status_choices, default=1, blank=True,
                                      null=True)
    company = models.CharField(verbose_name="目前就职公司", max_length=64, blank=True, null=True)
    salary = models.CharField(verbose_name="当前薪资", max_length=64, blank=True, null=True)

    date = models.DateField(verbose_name="咨询日期", auto_now_add=True)
    last_consult_date = models.DateField(verbose_name="最后跟进日期", auto_now_add=True)

    def __str__(self):
        return "姓名:{0},联系方式:{1}".format(self.name, self.qq, )


class ConsultRecord(models.Model):
    """
    客户跟进记录
    """
    customer = models.ForeignKey(verbose_name="客户", to='Customer')
    consultant = models.ForeignKey(verbose_name="课程顾问", to='UserInfo')
    note = models.TextField(verbose_name="跟进内容")
    date = models.DateField(verbose_name="跟进日期", auto_now_add=True)
crm中的models
{% extends 'layout.html' %}

{% block content %}
    <div class="luffy-container">
        <form class="form-horizontal clearfix" method="post" novalidate>
            {% csrf_token %}

            {% for field in form %}
                <div class="form-group col-sm-6 clearfix">
                    <label class="col-sm-3 control-label">{{ field.label }}</label>
                    <div class="col-sm-9">
                        {{ field }} <span style="color:firebrick;">{{ field.errors.0 }}</span>
                    </div>
                </div>
            {% endfor %}
            <div class="form-group col-sm-12">
                <div class="col-sm-6">
                    <div class="col-sm-offset-3">
                        <button type="submit" class="btn btn-primary">提 交</button>
                    </div>
                </div>
            </div>
        </form>
    </div>
{% endblock %}
增加修改通用的forms.html

总结:
1. 学会开发技能(通用)
2. 使用rbac组件(通用)

以后公司项目开发:
- 对rbac相关表:
- 菜单
- 权限
- 角色 (权限角色关系)

- 目前:权限信息的录入和分配(基于admin来做)

自己多加练习!完成自己的rbac项目
作业:写权限表中的增删改查(modelform实现) -ok

补充:2个补充???
1.login再优化,跳转到next界面!!!
2.注销--auth模块day19-20------1116ok
3.分页

这两周:分享(18-25号 部署)12.2--12.9号金融量化分析
admin用户登录:root root!2345
密码123 用户名冰冰、马金菊
8+3个表

'''

猜你喜欢

转载自www.cnblogs.com/lijie123/p/9971863.html