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個表'''
相關文章
相關標籤/搜索