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 }}期

4、客户表------------------从这开始看便可!!!开始写!!
--有些字段能够为空
--公户私户管理----课程顾问为空则为公户--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

5、用户登陆
用户登陆中间件--用户登陆白名单
#用户登陆,信息保存到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中配置

6、私户列表
1.按照报名状态排序,未报名在上面,负号表示倒序;
2.没法删除公司用户
3.私户添加应该增长到本身的页面,save以前设置一个值(课程顾客是我本身
form.instance.consultant_id = request.session['user_info']['id']),在models中不写
4.移至公户功能
7、跟进表--要限制只能查看本身的用户,拿到客户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

8、权限的应用---重点--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个表'''
相关文章
相关标签/搜索