CRM客戶關系管理系統(三)


第四章、kingadmin開發設計

 4.1.kingadmin設計

django admin注冊model的寫法

crm/admin.py

class CustomerAdmin(admin.ModelAdmin):
    #顯示
    list_display = ['name','source','contact_type','contact','consultant','consult_content','status','date']
    #過濾
    list_filter = ['source','consultant','status','date']
    #搜索,consultant是外鍵,必須加“__字段名”
    search_fields = ['contact','consultant__name']

admin.site.register(models.CustomerInfo,CustomerAdmin)

后台顯示

這是后台顯示的樣子,如果我們想讓前端也顯示類似這樣的頁面該怎么做呢?這就需要照django自帶的admin寫法,自己自定義個kingadmin(模仿admin)

 

kingadmin

(1)創建app kingadmin

python manage.py startapp kingadmin

添加到settings的INSTALL_APPS里面

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crm',
    'kingadmin',
]

因為想讓kingadmin app以后可以直接移植到其它項目中,所以在kingadmin目錄下單獨創建templates/kingadmin和static目錄,把之前的靜態文件和模板拷貝進去

 

(2) settings里面設置kingadmin靜態文件和templates路徑

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'statics'),
    os.path.join(BASE_DIR, 'kingadmin/statics'),  
)

 

(4)PerfectCRM/url.py添加路由分發

urlpatterns = [
    url(r'^kingadmin/', include('kingadmin.urls')),
]

 (5)kingamdin/urls.py

# kingadmin/urls.py

from django.conf.urls import url

from kingadmin import views

urlpatterns = [
    url(r'^login/', views.acc_login,name='login'),
    url(r'^logout/', views.acc_logout,name='logout'),
]

 

(6)kingamdin/views.py

 登錄界面也單獨創建

 

 

# kingadmin/views.py

from django.shortcuts import render,redirect
from django.contrib.auth import authenticate,login,logout

def acc_login(request):
    error_msg = ''
    if request.method == 'POST':
        username = request.POST.get('username',None)
        password = request.POST.get('password',None)
        #user是一個對象
        #驗證
        user = authenticate(username=username,password=password)
        if user:
            #登錄(已生成session)
            login(request, user)
            #如果有next值就獲取next值,沒有就跳轉到首頁
            return redirect(request.GET.get('next','/kingadmin/'))
        else:
            error_msg = '用戶名或密碼錯誤!'

    return render(request,'kingadmin/login.html',{'error_msg':error_msg})


def acc_logout(request):
    logout(request)
    return redirect("/login/")

 

(7)kingamdin/urls.py

添加登錄后跳轉到“app_index.html”頁面

urlpatterns = [
    url(r'^$', views.app_index,name='app_index'),
    url(r'^login/', views.acc_login,name='login'),
    url(r'^logout/', views.acc_logout,name='logout'),
]
    

(8)kingadmin/views.py

def app_index(request):
    return render(request,'kingadmin/app_index.html')

(9)kingadmin/app_index.html

 kingadmin/index.html中添加block right-content-container

king/index.html

 app_index.html

{#templates/kingadmin/app_index.html#}

{% extends 'kingadmin/index.html' %}

{% block right-content-container %}
    <h2 class="page-header">APPS</h2>
{% endblock %}

 

 

4.2.kingadmin自動發現及注冊功能開發

 想讓app_index.html頁面像后台一樣顯示所有注冊的app以及下面的表名

 

 

 

(1)kingadmin/app_setup.py

# kingadmin/app_setup.py

from django import conf

def kingadmin_auto_discover():
    for app_name in conf.settings.INSTALLED_APPS:
        try:
            #去每個app下面執行kingadmin.py文件
            mod = __import__('%s.kingadmin'%app_name)
            #打印每個app已注冊的model名字
            print(mod.kingadmin)
        except ImportError:
            pass

 

(2)crm/kingadmin.py

# crm/kingadmin.py


from kingadmin.sites import site
from crm import models

print('crm kingadmin....')

#注冊model
class CustomerAdmin(object):
    list_display = ['name','source','contact_type','contact','consultant','consult_content','status','date']
    list_filter = ['source','consultant','status','date']
    search_fields = ['contact','consultant__name']

site.register(models.CustomerInfo,CustomerAdmin)

(3)student/kingadmin.py

創建app student

student/models.py

# student/models.py

from django.db import models

class Test(models.Model):
    name = models.CharField(max_length=64)

student/kingadmin.py

# student/kingadmin.py

from student import models
from kingadmin.sites import site

print('student kingadmin.....')

#注冊model
class TestAdmin(object):
    list_display = ['name']

site.register(models.Test,TestAdmin)

(4)kingadmin/views.py

# kingadmin/views.py

from kingadmin import app_setup
#程序一啟動就自動執行
app_setup.kingadmin_auto_discover()

說明:

程序一啟動,會執行每個app下面的kingadmin.py,注冊全局的字典

 

from django import conf

conf.settings.INSTALL_APPS

動態獲取settings里面所有添加的app名字

 

運行程序

 

(5)返回全局字典

我們想要的字典格式如下:

修改sites.py

# kingadmin/sites.py

class AdminSite(object):
    def __init__(self):
        self.enable_admins = {}

    #兩個參數,一個表名,一個自定義的admin類
    def register(self,model_class,admin_class=None):
        '''注冊admin表'''

        # print('register',model_class,admin_class)
        #獲取app名字
        app_name = model_class._meta.app_label
        #獲取表名
        model_name = model_class._meta.model_name

        if app_name not in self.enable_admins:
            self.enable_admins[app_name] = {}
        self.enable_admins[app_name][model_name] = admin_class


#實例化,就可以調用register方法
site = AdminSite()

kingamdin/views.py中打印看看

from kingadmin import app_setup
#程序已啟動就自動執行
app_setup.kingadmin_auto_discover()

from kingadmin.sites import site
print('site',site.enable_admins)

運行程序

 

 (6)前端頁面顯示

 kingamdin/views.py

def app_index(request):

    return render(request,'kingadmin/app_index.html',{'site':site})

kingadmin/templates/app_index.html

{#templates/kingadmin/app_index.html#}

{% extends 'kingadmin/index.html' %}

{% block right-content-container %}
<h2 class="page-header">APPS</h2>

<div>
    {% for app_name,app_tables in site.enable_admins.items %}
        {{ app_name }}{{ app_tables }}

    {% endfor %}

</div>


{% endblock %}

 

 

4.3.kingadmin model obj list頁面開發

把前端頁面做成表格的格式,跟admin后台顯示一樣

 

bootstrap table:  https://v3.bootcss.com/css/#tables

 

(1)kingadmin/app_index.html

{#templates/kingadmin/app_index.html#}

{% extends 'kingadmin/index.html' %}

{% block right-content-container %}
<h2 class="page-header">APPS</h2>

<div>
    {% for app_name,app_tables in site.enable_admins.items %}
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>{{ app_name }}</th>
                </tr>
            </thead>
            <tbody>
                {% for model_name in app_tables  %}
                    <tr>
                        <td><a href="{% url 'table_obj_list' app_name model_name %}">{{ model_name }}</a></td>
                        <td>ADD</td>
                        <td>Change</td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    {% endfor %}

</div>


{% endblock %}

 

(2)crm/kingadmin.py注冊三個model

#注冊model
class CustomerAdmin(object):
    list_display = ['name','source','contact_type','contact','consultant','consult_content','status','date']
    list_filter = ['source','consultant','status','date']
    search_fields = ['contact','consultant__name']

site.register(models.CustomerInfo,CustomerAdmin)
site.register(models.Role)
site.register(models.Menus)
site.register(models.UserProfile)

 

(3)kingadmin/url.py

urlpatterns = [
        url(r'^(\w+)/(\w+)/$', views.table_obj_list,name='table_obj_list'),
]

 

(4)kingadmin/sites.py

class AdminSite(object):
    .
    .
    .
    def register(self,model_class,admin_class=None):
        .
        .
        .
         #獲取app名字
        app_name = model_class._meta.app_label
        #獲取表名
        model_name = model_class._meta.model_name
        #把model_class賦值給了admin_class,然后在視圖中可以通過admin_class找到對應的model類(表名字)
        admin_class.model = model_class
        .
        .
        .    

此時運行發現會報錯

 

是因為我們在注冊model的時候,有的寫了自定義的model類,有的沒寫,而我們都統一的賦值,導致那些沒寫自定義model類(空的)賦值的時候就會報NoneType錯誤

 

django自帶的自定義admin類的寫法繼承了ModelAdmin,那注冊的時候為什么有的沒寫自定義admin類沒有報錯呢?

是因為繼承的ModelAdmin幫我們寫了(里面其實都定義為空了),我們模仿django admin的寫法,也寫個父類。

 

 

(5)kingadmin/admin_base.py

新建個admin_base.py,寫個父類

# kingadmin/admin_base.py

class BaseKingAdmin(object):

    pass

 

(6)crm/kingadmin.py

# crm/kingadmin.py

from kingadmin.sites import site
from crm import models
from kingadmin.admin_base import BaseKingAdmin

# print('crm kingadmin....')

#注冊model
class CustomerAdmin(BaseKingAdmin):
    list_display = ['name','source','contact_type','contact','consultant','consult_content','status','date']
    list_filter = ['source','consultant','status','date']
    search_fields = ['contact','consultant__name']

site.register(models.CustomerInfo,CustomerAdmin)
site.register(models.Role)
site.register(models.Menus)
site.register(models.UserProfile)
crm/kingadmin.py

繼承BaseKingAdmin

 

 (7)kingadmin/sites.py

# kingadmin/sites.py
from kingadmin.admin_base import BaseKingAdmin

class AdminSite(object):
    def __init__(self):
        self.enable_admins = {}

    #兩個參數,一個表名,一個自定義的admin類
    def register(self,model_class,admin_class=BaseKingAdmin):
        '''注冊admin表'''

        # print('register',model_class,admin_class)
        #獲取app名字
        app_name = model_class._meta.app_label
        #獲取表名
        model_name = model_class._meta.model_name
        #把model_class賦值給了admin_class,然后在視圖中可以通過admin_class找到對應的model類(表名字)
        admin_class.model = model_class
        if app_name not in self.enable_admins:
            self.enable_admins[app_name] = {}
        self.enable_admins[app_name][model_name] = admin_class


#實例化,就可以調用register方法
site = AdminSite()
kingadmin/sites.py

 

現在運行程序,就正常了,訪問:http://127.0.0.1:8000/kingadmin/

 

(8)取出model里面的值

kingadmin/views.py

@login_required
def table_obj_list(request, app_name, model_name):
    '''取出指定model里的數據返回給前端'''
    #拿到admin_class后,通過它找到拿到model
    admin_class = site.enable_admins[app_name][model_name]
    querysets = admin_class.model.objects.all()

    return render(request, 'kingadmin/table_obj_list.html',{'querysets':querysets})

 

(9)templates/kingadmin/table_obj_list.html

{#kingadmin/templates/kingadmin/table_obj_list.html#}

{% extends 'kingadmin/index.html' %}

{% block right-content-container %}
<h2 class="page-header">app</h2>

<div>
        {{ querysets }}
        <table class="table table-striped">
            <thead>
                <tr>
                    <th></th>
                </tr>
            </thead>
            <tbody>

            </tbody>
        </table>
</div>

{% endblock %}

現在拿到的是一個對象,但是有個問題就是:沒注冊三個model里面得到值是一樣

 

 

 

因為沒注冊的三個mdoel都共享同一個BaseKingAdmin內存對象(三個model內存地址一樣),我們只需要實例化就可以了(實例化后就都有單獨的內存空間了)

修改kingadmin/sites.py

 

# kingadmin/sites.py
from kingadmin.admin_base import BaseKingAdmin

class AdminSite(object):
    def __init__(self):
        self.enable_admins = {}

    #兩個參數,一個表名,一個自定義的admin類
    def register(self,model_class,admin_class=None):
        '''注冊admin表'''

        # print('register',model_class,admin_class)
        #獲取app名字
        app_name = model_class._meta.app_label
        #獲取表名
        model_name = model_class._meta.model_name
        #把model_class賦值給了admin_class,然后在視圖中可以通過admin_class找到對應的model類(表名字)
        if not admin_class:
            # 實例化,如果沒寫注冊的類,就用BaseKingAdmin
            admin_class = BaseKingAdmin()
        else:
            #如果寫了注冊的類,就實例化自己
            admin_class = admin_class()
        admin_class.model = model_class
        if app_name not in self.enable_admins:
            self.enable_admins[app_name] = {}
        self.enable_admins[app_name][model_name] = admin_class

#實例化,就可以調用register方法
site = AdminSite()

 現在就可以取出對應model的數據了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM