python 全棧開發,Day114(裝飾器,排序規則,顯示列,添加按鈕,定製ModelForm,自定義列表頁面,自定製URL)

 

1、裝飾器

裝飾器本質上就是一個python函數,他可讓其餘函數在不須要作任何代碼變更的前提下,增長額外的功能,裝飾器的返回值也是一個函數對象。css

裝飾器的應用場景:好比插入日誌,性能測試,事務處理,緩存等等場景。html

基本裝飾器

不該用裝飾器前端

def wrapper(func):
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

def f1():
    print('f1')

print(f1.__name__)
View Code

執行輸出:python

f1

 

使用裝飾器jquery

def wrapper(func):
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

@wrapper
def f1():
    print('f1')

print(f1.__name__)
View Code

執行輸出:git

inner

咦?爲何輸出了inner,我要的是f1啊。由於函數裝飾以後,至關於執行了inner函數,因此輸出innergithub

爲了解決這個問題,須要調用一個模塊wrapsweb

高級裝飾器

wraps將 被修飾的函數(wrapped) 的一些屬性值賦值給 修飾器函數(wrapper) ,最終讓屬性的顯示更符合咱們的直覺!sql

導入模塊functools,並使用@functools.wraps,就可進行高級假裝數據庫

import functools
def wrapper(func):
    @functools.wraps(func)
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

@wrapper
def f1():
    print('f1')

print(f1.__name__)
View Code

執行輸出:

f1

雖然結果看起來是原來的,但真正執行的是inner
這個@functools.wraps裝飾器,保留原函數信息,好比函數名

若是之後寫裝飾器,必定要寫@functools.wraps!
後續flask會用到

 

2、排序規則

務必下載github代碼:

https://github.com/987334176/luffy_stark/archive/v1.0.zip

由於下面的內容,都是這份代碼來修改的!

 

修改stark-->server-->stark.py

注意:order_by是空列表,它須要用戶自定義

from django.conf.urls import url
from django.shortcuts import HttpResponse

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    order_by = []  # 須要排序的字段,由用戶自定義

    def get_order_by(self):
        return self.order_by  # 獲取排序列表

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        print(self.model_class)
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        print(queryset)
        return HttpResponse('stark list')

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改app02-->stark.py,定義order_by

# 這裏的site,指的是實例化後的變量名
# StarkConfig表示類
from stark.server.stark import site,StarkConfig
from app02 import models
from django.conf.urls import url
from django.shortcuts import HttpResponse

class RoleConfig(StarkConfig):
    order_by = ['-id']  # 有負號,表示降序

    def sk2(self, request):
        return HttpResponse('sk2神仙水')

    def extra_url(self):
        data = [
            url(r'^sk2/$', self.sk2),
        ]
        return data

site.register(models.Role,RoleConfig)  # 註冊表
View Code

 

添加數據

使用navicat打開app02_role表,添加2條數據

 

打開app01_userinfo表,添加2條數據

 

訪問頁面

http://127.0.0.1:8000/stark/app02/role/list/

效果以下:

查看Pycharm控制檯輸出:

<class 'app02.models.Role'>
<QuerySet [<Role: Role object>, <Role: Role object>]>

應該有一個頁面,要展現一下數據。那麼頁面,應該寫在哪裏?

要寫在stark裏面,由於它是組件,它是可以應用到其餘django項目的!

 

前端展現數據

進入stark應用目錄,建立目錄templates,在此目錄下建立stark目錄。在此目錄建立layout.html。這個是母版文件!

{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>路飛學城</title>
    <link rel="shortcut icon" href="{% static 'stark/imgs/luffy-study-logo.png' %} ">
    <link rel="stylesheet" href="{% static 'stark/plugins/bootstrap/css/bootstrap.css' %} "/>
    <link rel="stylesheet" href="{% static 'stark/plugins/font-awesome/css/font-awesome.css' %} "/>
    <link rel="stylesheet" href="{% static 'stark/css/commons.css' %} "/>
    <link rel="stylesheet" href="{% static 'stark/css/nav.css' %} "/>
    <style>
        body {
            margin: 0;
        }

        .no-radius {
            border-radius: 0;
        }

        .no-margin {
            margin: 0;
        }

        .pg-body > .left-menu {
            background-color: #EAEDF1;
            position: absolute;
            left: 0;
            top: 48px;
            bottom: 0;
            width: 220px;
            border: 1px solid #EAEDF1;
            overflow: auto;
        }

        .pg-body > .right-body {
            position: absolute;
            left: 225px;
            right: 0;
            top: 48px;
            bottom: 0;
            overflow: scroll;
            border: 1px solid #ddd;
            border-top: 0;
            font-size: 13px;
            min-width: 755px;
        }

        .navbar-right {
            float: right !important;
            margin-right: -15px;
        }

        .luffy-container {
            padding: 15px;
        }

    </style>
    {% block css %}{% endblock %}
</head>
<body>

<div class="pg-header">
    <div class="nav">
        <div class="logo-area left">
            <a href="#">
                <img class="logo" src="{% static 'stark/imgs/logo.svg' %}">
                <span style="font-size: 18px;">路飛學城 </span>
            </a>
        </div>

        <div class="left-menu left">
            <a class="menu-item">資產管理</a>
            <a class="menu-item">用戶信息</a>
            <a class="menu-item">路飛管理</a>
            <div class="menu-item">
                <span>使用說明</span>
                <i class="fa fa-caret-down" aria-hidden="true"></i>
                <div class="more-info">
                    <a href="#" class="more-item">管他什麼菜單</a>
                    <a href="#" class="more-item">實在是編不了</a>
                </div>
            </div>
        </div>

        <div class="right-menu right clearfix">

            <div class="user-info right">
                <a href="#" class="avatar">
                    <img class="img-circle" src="{% static 'stark/imgs/default.png' %}">
                </a>

                <div class="more-info">
                    <a href="#" class="more-item">我的信息</a>
                    <a href="/logout/" class="more-item">註銷</a>
                </div>
            </div>

            <a class="user-menu right">
                消息
                <i class="fa fa-commenting-o" aria-hidden="true"></i>
                <span class="badge bg-success">2</span>
            </a>

            <a class="user-menu right">
                通知
                <i class="fa fa-envelope-o" aria-hidden="true"></i>
                <span class="badge bg-success">2</span>
            </a>

            <a class="user-menu right">
                任務
                <i class="fa fa-bell-o" aria-hidden="true"></i>
                <span class="badge bg-danger">4</span>
            </a>
        </div>

    </div>
</div>
<div class="pg-body">
    <div class="left-menu">
        <div class="menu-body">

        </div>
    </div>
    <div class="right-body">
        <div>

        </div>
        {% block content %} {% endblock %}
    </div>
</div>


<script src="{% static 'stark/js/jquery-3.3.1.min.js' %} "></script>
<script src="{% static 'stark/plugins/bootstrap/js/bootstrap.js' %} "></script>
{% block js %} {% endblock %}
</body>
</html>
View Code

 

進入目錄stark-->templates-->stark,建立文件changelist.html

{% extends 'stark/layout.html' %}

{% block content %}
    <h1>列表頁面</h1>
    <div>
        <table class="table table-bordered">
            <thead>
                <tr>
                    <th>第一列</th>
                    <th>第二列</th>
                    <th>第三列</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>11</td>
                    <td>22</td>
                    <td>33</td>
                </tr>
            </tbody>
        </table>

    </div>



{% endblock %}
View Code

 

進入stark應用目錄,建立目錄static,再建立stark目錄

下載文件:

https://github.com/987334176/luffy_permission/archive/v1.5.zip

解壓文件,進入目錄web-->static,將裏面的css,imgs,js,plugins複製過來

 

項目結構以下:

這裏面刪除了css,js相關文件,不然結構長了!

luffy_stark/
├── app01
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── models.py
│   ├── stark.py
│   ├── tests.py
│   └── views.py
├── app02
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── models.py
│   ├── stark.py
│   ├── tests.py
│   └── views.py
├── db.sqlite3
├── luffy_stark
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
├── README.md
└── stark
    ├── admin.py
    ├── apps.py
    ├── __init__.py
    ├── models.py
    ├── server
    │   └── stark.py
    ├── static
    │   └── stark
    │       ├── css
    │       ├── imgs
    │       ├── js
    │       └── plugins
    ├── templates
    │   └── stark
    │       ├── changelist.html
    │       └── layout.html
    ├── tests.py
    └── views.py
View Code

注意:changelist.html是在stark-->templates-->stark目錄裏面!

 

修改stark-->server-->stark.py,渲染changelist.html

from django.conf.urls import url
from django.shortcuts import HttpResponse,render

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    order_by = []  # 須要排序的字段,由用戶自定義

    def get_order_by(self):
        return self.order_by  # 獲取排序列表

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        return render(request,'stark/changelist.html')

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

重啓django項目,訪問url:

http://127.0.0.1:8000/stark/app02/role/list/

效果以下:

 

2、顯示列

若是須要顯示自定義的列,怎麼作?

定義header_list和list_display,分別表示頭部和顯示的列。

修改stark-->server-->stark.py

from django.conf.urls import url
from django.shortcuts import HttpResponse,render

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    order_by = []  # 須要排序的字段,由用戶自定義

    def get_order_by(self):
        return self.order_by  # 獲取排序列表

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = ['id','username']  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name in list_display:
                # 獲取指定字段的verbose_name
                verbose_name = self.model_class._meta.get_field(name).verbose_name
                header_list.append(verbose_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據

            for name in list_display:
                # 使用反射獲取對象的值
                val = getattr(row, name)
                row_list.append(val)
            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

修改changelist.html,使用for循環

{% extends 'stark/layout.html' %}

{% block content %}
    <h1>列表頁面</h1>
    <div>
        <table class="table table-bordered">
            <thead>
                <tr>
                    {% for item in header_list %}
                    <th>{{ item }}</th>
                    {% endfor %}

                </tr>
            </thead>
            <tbody>
                {% for row_list in body_list %}
                <tr>
                    {% for col in row_list %}
                        <td>{{ col }}</td>
                    {% endfor %}

                </tr>
                {% endfor %}
            </tbody>
        </table>

    </div>



{% endblock %}
View Code

刷新頁面,效果以下:

 

去掉id

修改stark-->server-->stark.py,修改list_display 

list_display = ['username']

刷新頁面,效果以下:

 

這個變量,定死了。應該要動態生成才行。

修改stark-->server-->stark.py,定義靜態變量,定義方法get_list_display

from django.conf.urls import url
from django.shortcuts import HttpResponse,render

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name in list_display:
                # 獲取指定字段的verbose_name
                verbose_name = self.model_class._meta.get_field(name).verbose_name
                header_list.append(verbose_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據

            for name in list_display:
                # 使用反射獲取對象的值
                val = getattr(row, name)
                row_list.append(val)
            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改app02-->stark.py,設置list_display,只顯示title

# 這裏的site,指的是實例化後的變量名
# StarkConfig表示類
from stark.server.stark import site,StarkConfig
from app02 import models
from django.conf.urls import url
from django.shortcuts import HttpResponse

class RoleConfig(StarkConfig):
    order_by = ['-id']  # 有負號,表示降序
    list_display = ['title']  # 定義顯示的列

    def sk2(self, request):
        return HttpResponse('sk2神仙水')

    def extra_url(self):
        data = [
            url(r'^sk2/$', self.sk2),
        ]
        return data

site.register(models.Role,RoleConfig)  # 註冊表
View Code

刷新頁面,效果同上!

 

修改app01-->stark.py,增長自定義方法

from stark.server.stark import site,StarkConfig
from app01 import models

class UserInfoConfig(StarkConfig):
    list_display = ['id','username']

site.register(models.UserInfo,UserInfoConfig)
View Code

訪問url:   http://127.0.0.1:8000/stark/app01/userinfo/list/

效果以下:

 

若是用戶沒有指定list_display,那改如何顯示?直接顯示錶名和對象

修改stark-->server-->stark.py,作判斷。header_list顯示錶名,body_list顯示對象

from django.conf.urls import url
from django.shortcuts import HttpResponse,render

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name in list_display:
                # 獲取指定字段的verbose_name
                verbose_name = self.model_class._meta.get_field(name).verbose_name
                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name in list_display:
                # 使用反射獲取對象的值
                val = getattr(row, name)
                row_list.append(val)
            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改 app02-->stark.py,註釋掉list_display變量

訪問url:  http://127.0.0.1:8000/stark/app02/role/list/

 

可是顯示object,用戶會不爽,怎麼搞?

修改app02-->models.py,增長__str__方法,用來顯示默認字段

from django.db import models

# Create your models here.
class Role(models.Model):
    title = models.CharField(verbose_name="名稱", max_length=32)

    def __str__(self):
        return self.title
View Code

修改app01-->models.py,增長__str__方法

from django.db import models

# Create your models here.
class UserInfo(models.Model):
    username = models.CharField(verbose_name="用戶名",max_length=32)
    
    def __str__(self):
        return self.username
View Code

 

刷新頁面,效果以下:

 

注意:在stark-->server-->stark.py 中定義的get_list_display方法,是一個預留的鉤子。它能夠作定製化

在app01-->stark.py裏面定義了list_display,默認是全部用戶,都顯示這些列。

若是須要根據用戶角色不一樣來展現不一樣的數據呢?那麼這個鉤子,就能夠派上用場了!

能夠直接在app01-->stark.py裏面,重構get_list_display方法。

好比:

修改app02-->stark.py

注意:get_list_display裏面的if 1 == 1,只是爲了作演示而已。實際上,應該是你的業務代碼!

# 這裏的site,指的是實例化後的變量名
# StarkConfig表示類
from stark.server.stark import site,StarkConfig
from app02 import models
from django.conf.urls import url
from django.shortcuts import HttpResponse

class RoleConfig(StarkConfig):
    order_by = ['-id']  # 有負號,表示降序
    # list_display = ['id','title']  # 定義顯示的列
    def get_list_display(self):
        if 1 == 1:
            return ['id']
        else:
            return ['id','title']

    def sk2(self, request):
        return HttpResponse('sk2神仙水')

    def extra_url(self):
        data = [
            url(r'^sk2/$', self.sk2),
        ]
        return data

site.register(models.Role,RoleConfig)  # 註冊表
View Code

注意:list_display和get_list_display不能同時存在。由於list_display的優先級比get_list_display高

定義了list_display,那麼get_list_display就沒有效果了!

 

訪問url:  http://127.0.0.1:8000/stark/app02/role/list/

效果以下:

 

修改app01-->models.py,增長部門表

from django.db import models

# Create your models here.
class UserInfo(models.Model):
    username = models.CharField(verbose_name="用戶名",max_length=32)

    def __str__(self):
        return self.username

class Depart(models.Model):

    name = models.CharField(verbose_name='部門名稱',max_length=32)
    tel = models.CharField(verbose_name='聯繫電話',max_length=31)
    user = models.ForeignKey(verbose_name='負責人',to='UserInfo')

    def __str__(self):
        return self.name
View Code

使用2個命令生成表

python manage.py makemigrations
python manage.py migrate

注意:若是沒法生成表depart,使用命令

python manage.py makemigrations app01
python manage.py migrate

 

添加2條記錄

 

修改app01-->stark.py,註冊表Depart

from stark.server.stark import site,StarkConfig
from app01 import models

class UserInfoConfig(StarkConfig):
    list_display = ['id','username']

site.register(models.UserInfo,UserInfoConfig)
site.register(models.Depart)
View Code

訪問部門的url:  http://127.0.0.1:8000/stark/app01/depart/list/

效果以下:

 

修改app01-->stark.py,爲depart增長list_display

from stark.server.stark import site,StarkConfig
from app01 import models

class UserInfoConfig(StarkConfig):
    list_display = ['id','username']

class DepartConfig(StarkConfig):
    list_display = ['name','tel','user']

site.register(models.UserInfo,UserInfoConfig)
site.register(models.Depart,DepartConfig)
View Code

千萬要記得在site.register,添加自定義類!不然下面的效果出不來!

刷新頁面,效果以下:

 

查看stark-->server-->stark.py,查看changelist_view,發現代碼都寫在這裏了。可讀性很差!

若是要增長其餘功能呢?好比下面的效果:

那麼就須要拆分代碼,不一樣的功能,放在不一樣的方法裏面!

 

4、添加按鈕

CheckBox

以部門表爲例,加一個checkbox,也就是複選框

修改 app01-->stark.py,增長一個方法,添加到列表中

from stark.server.stark import site,StarkConfig
from app01 import models

class UserInfoConfig(StarkConfig):
    list_display = ['id','username']

class DepartConfig(StarkConfig):
    def f1(self):  # 測試函數
        pass

    list_display = [f1,'name', 'tel', 'user']

site.register(models.UserInfo,UserInfoConfig)
site.register(models.Depart,DepartConfig)
View Code

 

修改 stark-->server-->stark.py,對list_display每個元素作判斷。

若是是字符串,去數據庫取。若是是函數,去用戶自定義的方法中獲取!使用FunctionType判斷

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self)  # 執行函數獲取
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改app01-->stark.py,增長方法f1

from stark.server.stark import site,StarkConfig
from app01 import models

class UserInfoConfig(StarkConfig):
    list_display = ['id','username']

class DepartConfig(StarkConfig):
    def f1(self,header=False):  # 測試函數
        if header:
            # 輸出中文
            return "選擇"

        return "checkbox"  # 標籤名

    list_display = [f1,'name', 'tel', 'user']

site.register(models.UserInfo,UserInfoConfig)
site.register(models.Depart,DepartConfig)
View Code

訪問頁面:http://127.0.0.1:8000/stark/app01/depart/list/

效果以下:

 

這個checkbox看着不爽,要換成html標籤。須要使用mark_safe渲染html標籤

修改app01-->stark.py,返回一個input標籤

from stark.server.stark import site,StarkConfig
from app01 import models
from django.utils.safestring import mark_safe

class UserInfoConfig(StarkConfig):
    list_display = ['id','username']

class DepartConfig(StarkConfig):
    def f1(self,header=False):  # 測試函數
        if header:
            # 輸出標籤
            return mark_safe('<input type="checkbox" name="pk" />')

        return mark_safe('<input type="checkbox" name="pk" />')  # 標籤名

    list_display = [f1,'name', 'tel', 'user']

site.register(models.UserInfo,UserInfoConfig)
site.register(models.Depart,DepartConfig)
View Code

 

 刷新頁面,效果以下:

可是有一個問題,input標籤的值和行數據的id不匹配。怎麼動態獲取呢?

在stark-->server-->stark.py裏面,給它傳一個row對象,就能夠獲取了!

修改stark-->server-->stark.py,傳遞row參數

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改app01-->stark.py,接收row參數

f1的名字很差,要改爲display_checkbox

from stark.server.stark import site,StarkConfig
from app01 import models
from django.utils.safestring import mark_safe

class UserInfoConfig(StarkConfig):
    list_display = ['id','username']

class DepartConfig(StarkConfig):
    def f1(self,row=None,header=False):  # 測試函數
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    list_display = [f1,'name', 'tel', 'user']

site.register(models.UserInfo,UserInfoConfig)
site.register(models.Depart,DepartConfig)
View Code

刷新頁面,效果以下:

id就動態生成了!

之後有form表單,後臺就能夠批量操做了

 

如今role表也想有checkbox功能,怎麼辦?代碼copy一遍?

這樣很差,若是有10個表呢?須要寫在StarkConfig類裏面!

爲何呢?由於在app01-->stark.py裏面的自定義類,都是繼承了StarkConfig類

 

修改stark-->server-->stark.py,在StarkConfig類增長display_checkbox方法

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改app01-->stark.py,使用StarkConfig類的display_checkbox方法

from stark.server.stark import site,StarkConfig
from app01 import models

class UserInfoConfig(StarkConfig):
    list_display = ['id','username']

class DepartConfig(StarkConfig):
    list_display = [StarkConfig.display_checkbox,'name', 'tel', 'user']

site.register(models.UserInfo,UserInfoConfig)
site.register(models.Depart,DepartConfig)
View Code

刷新頁面,效果同上!

 

修改app02-->stark.py,使用display_checkbox方法

# 這裏的site,指的是實例化後的變量名
# StarkConfig表示類
from stark.server.stark import site,StarkConfig
from app02 import models
from django.conf.urls import url
from django.shortcuts import HttpResponse

class RoleConfig(StarkConfig):
    order_by = ['-id']  # 有負號,表示降序
    # 定義顯示的列
    list_display = [StarkConfig.display_checkbox,'id','title']
    # def get_list_display(self):  # 鉤子函數,用來作定製顯示
    #     if 1 == 1:
    #         return ['id']
    #     else:
    #         return ['id','title']

    def sk2(self, request):
        return HttpResponse('sk2神仙水')

    def extra_url(self):
        data = [
            url(r'^sk2/$', self.sk2),
        ]
        return data

site.register(models.Role,RoleConfig)  # 註冊表
View Code

訪問url:    http://127.0.0.1:8000/stark/app02/role/list/

效果以下:

 

編輯和刪除

修改stark-->server-->stark.py,增長編輯和刪除方法

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"
        return mark_safe('<a href="/edit/%s">編輯</a>' % row.pk)

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"
        return mark_safe('<a href="/del/%s">刪除</a>' % row.pk)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改app01-->stark.py,應用編輯和刪除

from stark.server.stark import site, StarkConfig
from app01 import models


class UserInfoConfig(StarkConfig):
    list_display = ['id', 'username']


class DepartConfig(StarkConfig):
    list_display = [StarkConfig.display_checkbox, 'name', 'tel', 'user', StarkConfig.display_edit,
                    StarkConfig.display_del]


site.register(models.UserInfo, UserInfoConfig)
site.register(models.Depart, DepartConfig)
View Code

重啓django項目,訪問頁面:  http://127.0.0.1:8000/stark/app01/depart/list/

效果以下:

 

文字看着不爽,改爲圖標

修改stark-->server-->stark.py

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"
        return mark_safe('<a href="/edit/%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % row.pk)

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"
        return mark_safe('<a href="/del/%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % row.pk)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

刷新頁面,效果以下:

 

編輯和刪除,佔用太寬了。合併成一列!

修改stark-->server-->stark.py,增長方法display_edit_del

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"
        return mark_safe('<a href="/edit/%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % row.pk)

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"
        return mark_safe('<a href="/del/%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % row.pk)

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="/edit/%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="/del/%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (row.pk, row.pk,)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        # print(info)
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改app01-->stark.py,應用方法display_edit_del

from stark.server.stark import site, StarkConfig
from app01 import models


class UserInfoConfig(StarkConfig):
    list_display = ['id', 'username']


class DepartConfig(StarkConfig):
    list_display = [StarkConfig.display_checkbox, 'name', 'tel', 'user', StarkConfig.display_edit_del]


site.register(models.UserInfo, UserInfoConfig)
site.register(models.Depart, DepartConfig)
View Code

刷新頁面,效果以下:

經過這樣,想顯示 編輯、刪除、編輯和刪除。均可以任意選擇!

 

可是有一個問題,url不對。怎麼辦?應該使用url別名反向生成。

看這一段代碼

info = self.model_class._meta.app_label, self.model_class._meta.model_name
urlpatterns = [
    url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
    ...
]

別名須要app名和表名,以及命令空間。再拼接_changelist,就能夠反向生成url了

 

修改stark-->server-->stark.py,增長方法reverse_edit_url方法。並在編輯的方法中,使用此方法獲取url

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"
        return mark_safe('<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"
        return mark_safe('<a href="/del/%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % row.pk)

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="/del/%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), row.pk,)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

重啓django項目,訪問url: http://127.0.0.1:8000/stark/app01/depart/list/

能夠發現url生成了,效果以下:

點擊編輯按鈕,會自動跳轉頁面

http://127.0.0.1:8000/stark/app01/depart/1/change/

效果以下:

 

 

 那麼刪除也是一樣的,再定義一個方法reverse_del_url方法。並在刪除的方法中,使用此方法獲取url

 修改stark-->server-->stark.py

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"

        return mark_safe(
            '<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"

        return mark_safe(
            '<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), self.reverse_del_url(row),)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串,這裏爲change
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    def reverse_del_url(self, row):  # 反向生成刪除行內容的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        # 注意:這裏爲del
        name = '%s:%s_%s_del' % (namespace, app_label, model_name)
        del_url = reverse(name, kwargs={'pk': row.pk})
        return del_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 刷新頁面,效果以下:

 

點擊刪除按鈕,會自動跳轉頁面

http://127.0.0.1:8000/stark/app01/depart/1/del/

效果以下:

那麼其餘頁面,也是一樣的效果!

 

添加按鈕

修改stark-->templates-->stark-->changelist.html ,先寫一個添加按鈕

{% extends 'stark/layout.html' %}

{% block content %}
    <h1>列表頁面</h1>
    <div>
        <div style="margin: 5px 0;">
            <a href="#" class="btn btn-success">添加</a>
        </div>
        <table class="table table-bordered">
            <thead>
                <tr>
                    {% for item in header_list %}
                    <th>{{ item }}</th>
                    {% endfor %}

                </tr>
            </thead>
            <tbody>
                {% for row_list in body_list %}
                <tr>
                    {% for col in row_list %}
                        <td>{{ col }}</td>
                    {% endfor %}

                </tr>
                {% endfor %}
            </tbody>
        </table>

    </div>



{% endblock %}
View Code

訪問頁面: http://127.0.0.1:8000/stark/app01/depart/list/

效果以下:

可是,並非每一個頁面,都須要顯示添加按鈕。如何控制頁面顯示呢?

 

 

修改stark-->server-->stark.py,增長get_add_btn方法

注意:在渲染stark/changelist.html頁面時,要傳入參數add_btn

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"

        return mark_safe(
            '<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"

        return mark_safe(
            '<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), self.reverse_del_url(row),)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def get_add_btn(self):  # 顯示添加按鈕
        return mark_safe('<a href="#" class="btn btn-success">添加</a>')

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())

        add_btn = self.get_add_btn()  # 添加按鈕返回值,不爲空展現,不然不展現
        
        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        # 注意:要傳入add_btn
        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list,'add_btn':add_btn})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串,這裏爲change
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    def reverse_del_url(self, row):  # 反向生成刪除行內容的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        # 注意:這裏爲del
        name = '%s:%s_%s_del' % (namespace, app_label, model_name)
        del_url = reverse(name, kwargs={'pk': row.pk})
        return del_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

修改app01-->stark.py,重構get_add_btn方法,返回None

from stark.server.stark import site, StarkConfig
from app01 import models


class UserInfoConfig(StarkConfig):
    list_display = ['id', 'username']


class DepartConfig(StarkConfig):
    list_display = [StarkConfig.display_checkbox, 'name', 'tel', 'user', StarkConfig.display_edit_del]
    
    def get_add_btn(self):  # 返回None,表示不顯示添加按鈕
        pass

site.register(models.UserInfo, UserInfoConfig)
site.register(models.Depart, DepartConfig)
View Code

 

修改stark-->templates-->stark-->changelist.html,作一個if判斷。若是get_add_btn返回結果不爲空,則展現。不然不顯示!

{% extends 'stark/layout.html' %}

{% block content %}
    <h1>列表頁面</h1>
    <div>
        {% if add_btn %}
        <div style="margin: 5px 0;">
            {{ add_btn }}
        </div>
        {% endif %}
        <table class="table table-bordered">
            <thead>
                <tr>
                    {% for item in header_list %}
                    <th>{{ item }}</th>
                    {% endfor %}

                </tr>
            </thead>
            <tbody>
                {% for row_list in body_list %}
                <tr>
                    {% for col in row_list %}
                        <td>{{ col }}</td>
                    {% endfor %}

                </tr>
                {% endfor %}
            </tbody>
        </table>

    </div>



{% endblock %}
View Code

刷新頁面,就沒有添加按鈕了,效果以下:

那麼其餘頁面,是有的,訪問頁面: 

 

可是連接不對,得生成url

 

修改stark-->server-->stark.py,增長reverse_add_url方法

並修改get_add_btn,執行reverse_add_url方法

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"

        return mark_safe(
            '<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"

        return mark_safe(
            '<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), self.reverse_del_url(row),)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def get_add_btn(self):  # 顯示添加按鈕
        return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())

        add_btn = self.get_add_btn()  # 添加按鈕返回值,不爲空展現,不然不展現

        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        # 注意:要傳入add_btn
        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list,'add_btn':add_btn})

    def add_view(self, request):
        return HttpResponse('stark add')

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_add_url(self):  # 反向生成添加url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_add' % (namespace, app_label, model_name)
        add_url = reverse(name)
        return add_url

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串,這裏爲change
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    def reverse_del_url(self, row):  # 反向生成刪除行內容的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        # 注意:這裏爲del
        name = '%s:%s_%s_del' % (namespace, app_label, model_name)
        del_url = reverse(name, kwargs={'pk': row.pk})
        return del_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

訪問url:  http://127.0.0.1:8000/stark/app01/userinfo/list/

點擊添加按鈕,頁面跳轉

那麼頁面的添加按鈕,連接是不同的。

5、定製ModelForm

添加數據

問題來了,若是是添加,這個頁面應該有幾個input框?

每一個頁面,都須要作表單驗證,還有默認選中狀態

這就須要用到ModelForm

要爲每個model生成類,還得須要實例化。好比這樣

class xxxModelForm(ModelForm):
    class Meta:
        model = xxx
        field = ['id','xx']

 

修改stark-->server-->stark.py,增長類 AddModelForm,並渲染頁面change.html

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse
from django import forms

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"

        return mark_safe(
            '<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"

        return mark_safe(
            '<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), self.reverse_del_url(row),)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def get_add_btn(self):  # 顯示添加按鈕
        return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())

        add_btn = self.get_add_btn()  # 添加按鈕返回值,不爲空展現,不然不展現

        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        # 注意:要傳入add_btn
        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list,'add_btn':add_btn})

    def add_view(self, request):
        """
        全部的添加頁面,都在此方法處理
        使用ModelForm實現
        :param request:
        :return:
        """

        class AddModelForm(forms.ModelForm):
            class Meta:
                model = self.model_class
                fields = "__all__"

        if request.method == "GET":
            form = AddModelForm()
            return render(request,'stark/change.html',{'form':form})

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_add_url(self):  # 反向生成添加url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_add' % (namespace, app_label, model_name)
        add_url = reverse(name)
        return add_url

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串,這裏爲change
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    def reverse_del_url(self, row):  # 反向生成刪除行內容的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        # 注意:這裏爲del
        name = '%s:%s_%s_del' % (namespace, app_label, model_name)
        del_url = reverse(name, kwargs={'pk': row.pk})
        return del_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

進入目錄 stark-->templates-->stark,建立文件change.html

寫一個form表單,使用for循環

{% extends 'stark/layout.html' %}
{% block css %}
    <style>
        .change input,select {
            display: block;
            width: 100%;
            height: 34px;
            padding: 6px 12px;
            font-size: 14px;
            line-height: 1.42857143;
            color: #555;
            background-color: #fff;
            background-image: none;
            border: 1px solid #ccc;
            border-radius: 4px;
            -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
            -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
            -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
            transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
        }
    </style>

{% endblock %}
{% block content %}
    <div style="width: 680px;margin: 0 auto;">
        <form class="change" method="post">
            {% csrf_token %}
            {% for filed in form %}
                <div class="form-group">
                    <label>{{ filed.label }}</label>
                    {{ filed }}
                    {{ filed.errors.0 }}
                </div>
            {% endfor %}

            <button type="submit" class="btn btn-default">Submit</button>
        </form>
    </div>
{% endblock %}
View Code

 

修改app01-->stark.py,註釋get_add_btn方法。讓它顯示添加按鈕

from stark.server.stark import site, StarkConfig
from app01 import models


class UserInfoConfig(StarkConfig):
    list_display = ['id', 'username']


class DepartConfig(StarkConfig):
    list_display = [StarkConfig.display_checkbox, 'name', 'tel', 'user', StarkConfig.display_edit_del]

    # def get_add_btn(self):  # 返回None,表示不顯示添加按鈕
    #     pass

site.register(models.UserInfo, UserInfoConfig)
site.register(models.Depart, DepartConfig)
View Code

 

重啓django項目,訪問頁面:  http://127.0.0.1:8000/stark/app01/depart/list/

點擊添加按鈕,效果以下:

點擊提交,沒有任何效果。

 

修改stark-->server-->stark.py,修改add_view方法。爲post時,保存數據

添加reverse_list_url方法,用來作保存以後的跳轉

from django.conf.urls import url
from django.shortcuts import HttpResponse,render,redirect
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse
from django import forms

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"

        return mark_safe(
            '<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"

        return mark_safe(
            '<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), self.reverse_del_url(row),)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def get_add_btn(self):  # 顯示添加按鈕
        return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())

        add_btn = self.get_add_btn()  # 添加按鈕返回值,不爲空展現,不然不展現

        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        # 注意:要傳入add_btn
        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list,'add_btn':add_btn})

    def add_view(self, request):
        """
        全部的添加頁面,都在此方法處理
        使用ModelForm實現
        :param request:
        :return:
        """

        class AddModelForm(forms.ModelForm):
            class Meta:
                model = self.model_class
                fields = "__all__"

        if request.method == "GET":
            form = AddModelForm()
            return render(request,'stark/change.html',{'form':form})

        form = AddModelForm(request.POST)  # 接收POST數據
        if form.is_valid():  # 驗證數據
            form.save()  # 自動保存數據
            # 反向生成url,跳轉到列表頁面
            return redirect(self.reverse_list_url())
        # 渲染頁面,此時會保存表單數據
        return render(request, 'stark/change.html', {'form': form})

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_list_url(self):  # 反向生成訪問列表的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_changelist' % (namespace, app_label, model_name)
        list_url = reverse(name)
        return list_url

    def reverse_add_url(self):  # 反向生成添加url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_add' % (namespace, app_label, model_name)
        add_url = reverse(name)
        return add_url

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串,這裏爲change
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    def reverse_del_url(self, row):  # 反向生成刪除行內容的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        # 注意:這裏爲del
        name = '%s:%s_%s_del' % (namespace, app_label, model_name)
        del_url = reverse(name, kwargs={'pk': row.pk})
        return del_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

重啓django項目,訪問添加頁面: http://127.0.0.1:8000/stark/app01/depart/add/

添加一條數據,點擊提交

頁面會自動跳轉,添加的數據,就能夠看到了!

 

這樣不夠好,其餘方法要使用ModelForm呢?好比編輯

修改stark-->server-->stark.py,定義get_model_form_class方法,將add_view方法中的AddModelForm類抽離出來

from django.conf.urls import url
from django.shortcuts import HttpResponse,render,redirect
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse
from django import forms

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"

        return mark_safe(
            '<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"

        return mark_safe(
            '<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), self.reverse_del_url(row),)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義
    model_form_class = None  # form組件須要的model_class

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def get_add_btn(self):  # 顯示添加按鈕
        return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())

    def get_model_form_class(self):
        """
        獲取ModelForm類
        :return:
        """
        if self.model_form_class:
            return self.model_form_class

        class AddModelForm(forms.ModelForm):
            class Meta:
                model = self.model_class
                fields = "__all__"

        return AddModelForm

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())

        add_btn = self.get_add_btn()  # 添加按鈕返回值,不爲空展現,不然不展現

        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        # 注意:要傳入add_btn
        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list,'add_btn':add_btn})

    def add_view(self, request):
        """
        全部的添加頁面,都在此方法處理
        使用ModelForm實現
        :param request:
        :return:
        """
        # 添加數據,使用ModelForm
        AddModelForm = self.get_model_form_class()

        if request.method == "GET":
            form = AddModelForm()
            return render(request,'stark/change.html',{'form':form})

        form = AddModelForm(request.POST)  # 接收POST數據
        if form.is_valid():  # 驗證數據
            form.save()  # 自動保存數據
            # 反向生成url,跳轉到列表頁面
            return redirect(self.reverse_list_url())
        # 渲染頁面,此時會保存表單數據
        return render(request, 'stark/change.html', {'form': form})

    def change_view(self, request, pk):
        return HttpResponse('stark change')

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_list_url(self):  # 反向生成訪問列表的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_changelist' % (namespace, app_label, model_name)
        list_url = reverse(name)
        return list_url

    def reverse_add_url(self):  # 反向生成添加url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_add' % (namespace, app_label, model_name)
        add_url = reverse(name)
        return add_url

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串,這裏爲change
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    def reverse_del_url(self, row):  # 反向生成刪除行內容的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        # 注意:這裏爲del
        name = '%s:%s_%s_del' % (namespace, app_label, model_name)
        del_url = reverse(name, kwargs={'pk': row.pk})
        return del_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

測試添加功能,訪問如下url: 

 http://127.0.0.1:8000/stark/app01/userinfo/list/

點擊添加

 

添加一條數據

發現數據有了

 

修改 app01-->stark.py,自定義form類,添加DepartModelForm

from stark.server.stark import site, StarkConfig
from app01 import models
from django import forms

class UserInfoConfig(StarkConfig):
    list_display = ['id', 'username']


class DepartModelForm(forms.ModelForm):
    class Meta:
        model = models.Depart
        fields = "__all__"

    def clean_name(self):  # 定義鉤子
        print(self.cleaned_data['name'])
        return self.cleaned_data['name']

class DepartConfig(StarkConfig):
    list_display = [StarkConfig.display_checkbox, 'name', 'tel', 'user', StarkConfig.display_edit_del]
    model_form_class = DepartModelForm
    # def get_add_btn(self):  # 返回None,表示不顯示添加按鈕
    #     pass

site.register(models.UserInfo, UserInfoConfig)
site.register(models.Depart, DepartConfig)
View Code

 

訪問url: 

 http://127.0.0.1:8000/stark/app01/depart/list/

點擊添加按鈕,添加一條數據

 

提交以後,頁面跳轉,數據就出來了

查看Pycharm控制檯輸出:

運營部

說明它,走到了clean_name鉤子。那麼表示,app01-->stark.py自定義的ModelForm類生效了!

 

編輯數據

修改stark-->server-->stark.py,修改change_view方法

from django.conf.urls import url
from django.shortcuts import HttpResponse,render,redirect
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse
from django import forms

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"

        return mark_safe(
            '<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"

        return mark_safe(
            '<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), self.reverse_del_url(row),)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義
    model_form_class = None  # form組件須要的model_class

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def get_add_btn(self):  # 顯示添加按鈕
        return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())

    def get_model_form_class(self):
        """
        獲取ModelForm類
        :return:
        """
        if self.model_form_class:
            return self.model_form_class

        class AddModelForm(forms.ModelForm):
            class Meta:
                model = self.model_class
                fields = "__all__"

        return AddModelForm

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())

        add_btn = self.get_add_btn()  # 添加按鈕返回值,不爲空展現,不然不展現

        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        # 注意:要傳入add_btn
        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list,'add_btn':add_btn})

    def add_view(self, request):
        """
        全部的添加頁面,都在此方法處理
        使用ModelForm實現
        :param request:
        :return:
        """
        # 添加數據,使用ModelForm
        AddModelForm = self.get_model_form_class()

        if request.method == "GET":
            form = AddModelForm()
            return render(request,'stark/change.html',{'form':form})

        form = AddModelForm(request.POST)  # 接收POST數據
        if form.is_valid():  # 驗證數據
            form.save()  # 自動保存數據
            # 反向生成url,跳轉到列表頁面
            return redirect(self.reverse_list_url())
        # 渲染頁面,此時會保存表單數據
        return render(request, 'stark/change.html', {'form': form})

    def change_view(self, request, pk):
        """
        全部編輯頁面
        :param request:
        :param pk:
        :return:
        """
        # 查看單條數據
        obj = self.model_class.objects.filter(pk=pk).first()
        if not obj:
            return HttpResponse('數據不存在')
        # 獲取model_form類
        ModelFormClass = self.get_model_form_class()
        if request.method == 'GET':
            # instance表示生成默認值
            form = ModelFormClass(instance=obj)
            # 渲染頁面,添加和修改能夠共用一個一個模板文件
            return render(request, 'stark/change.html', {'form': form})
        # instance = obj 表示指定給誰作修改
        form = ModelFormClass(data=request.POST, instance=obj)
        if form.is_valid():
            form.save()  # 修改數據
            # 跳轉到列表頁面
            return redirect(self.reverse_list_url())
        return render(request, 'stark/change.html', {'form': form})

    def delete_view(self, request, pk):
        return HttpResponse('stark delete')

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_list_url(self):  # 反向生成訪問列表的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_changelist' % (namespace, app_label, model_name)
        list_url = reverse(name)
        return list_url

    def reverse_add_url(self):  # 反向生成添加url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_add' % (namespace, app_label, model_name)
        add_url = reverse(name)
        return add_url

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串,這裏爲change
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    def reverse_del_url(self, row):  # 反向生成刪除行內容的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        # 注意:這裏爲del
        name = '%s:%s_%s_del' % (namespace, app_label, model_name)
        del_url = reverse(name, kwargs={'pk': row.pk})
        return del_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

注意:添加和編輯,能夠共用一個模板文件。由於它們都是用的ModelForm組件

 

訪問頁面: http://127.0.0.1:8000/stark/app01/depart/list/

修改一條數據,好比人事部

點擊提交,數據就修改過來了

 

刪除數據

刪除,得彈出一個模態框,要用戶提示才行

若是是一個GET請求,讓用戶看到一個頁面

修改stark-->server-->stark.py,修改delete_view方法

from django.conf.urls import url
from django.shortcuts import HttpResponse,render,redirect
from types import FunctionType
from django.utils.safestring import mark_safe
from django.urls import reverse
from django import forms

class StarkConfig(object):
    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site

    def display_checkbox(self,row=None,header=False):  # 顯示覆選框
        if header:
            # 輸出中文
            return "選擇"
        # 注意:這裏要寫row.pk,不能寫row.id。你不能保證每個表的主鍵都是id
        return mark_safe('<input type="checkbox" name="pk" values="%s"/>' %row.pk)

    def display_edit(self, row=None, header=False):
        if header:
            return "編輯"

        return mark_safe(
            '<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row))

    def display_del(self, row=None, header=False):
        if header:
            return "刪除"

        return mark_safe(
            '<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row))

    def display_edit_del(self, row=None, header=False):
        if header:
            return "操做"
        tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> |
        <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
        """ % (self.reverse_edit_url(row), self.reverse_del_url(row),)
        return mark_safe(tpl)

    order_by = []  # 須要排序的字段,由用戶自定義
    list_display = []  # 定義顯示的列,由用戶自定義
    model_form_class = None  # form組件須要的model_class

    def get_order_by(self):  # 獲取排序列表
        return self.order_by

    def get_list_display(self):  # 獲取顯示的列
        return self.list_display

    def get_add_btn(self):  # 顯示添加按鈕
        return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())

    def get_model_form_class(self):
        """
        獲取ModelForm類
        :return:
        """
        if self.model_form_class:
            return self.model_form_class

        class AddModelForm(forms.ModelForm):
            class Meta:
                model = self.model_class
                fields = "__all__"

        return AddModelForm

    def changelist_view(self, request):
        """
        全部URL查看列表頁面
        :param request:
        :return:
        """
        # 根據排序列表進行排序
        queryset = self.model_class.objects.all().order_by(*self.get_order_by())

        add_btn = self.get_add_btn()  # 添加按鈕返回值,不爲空展現,不然不展現

        list_display = self.list_display  # 定義顯示的列
        header_list = []  # 定義頭部,用來顯示verbose_name
        if list_display:
            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    # 執行函數,默認顯示中文
                    verbose_name = name_or_func(self,header=True)
                else:
                    # 獲取指定字段的verbose_name
                    verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name

                header_list.append(verbose_name)
        else:
            # 若是list_display爲空,添加表名
            header_list.append(self.model_class._meta.model_name)

        body_list = []  # 顯示內容

        for row in queryset:
            # 這裏的row是對象,它表示表裏面的一條數據
            row_list = []  # 展現每一行數據
            if not list_display:  # 若是不在list_display裏面
                # 添加對象
                row_list.append(row)
                body_list.append(row_list)
                continue

            for name_or_func in list_display:
                if isinstance(name_or_func,FunctionType):
                    val = name_or_func(self,row=row)  # 執行函數獲取,傳遞row對象
                else:
                    # 使用反射獲取對象的值
                    val = getattr(row, name_or_func)

                row_list.append(val)

            body_list.append(row_list)

        # 注意:要傳入add_btn
        return render(request,'stark/changelist.html',{'header_list':header_list,'body_list':body_list,'add_btn':add_btn})

    def add_view(self, request):
        """
        全部的添加頁面,都在此方法處理
        使用ModelForm實現
        :param request:
        :return:
        """
        # 添加數據,使用ModelForm
        AddModelForm = self.get_model_form_class()

        if request.method == "GET":
            form = AddModelForm()
            return render(request,'stark/change.html',{'form':form})

        form = AddModelForm(request.POST)  # 接收POST數據
        if form.is_valid():  # 驗證數據
            form.save()  # 自動保存數據
            # 反向生成url,跳轉到列表頁面
            return redirect(self.reverse_list_url())
        # 渲染頁面,此時會保存表單數據
        return render(request, 'stark/change.html', {'form': form})

    def change_view(self, request, pk):
        """
        全部編輯頁面
        :param request:
        :param pk:
        :return:
        """
        # 查看單條數據
        obj = self.model_class.objects.filter(pk=pk).first()
        if not obj:
            return HttpResponse('數據不存在')
        # 獲取model_form類
        ModelFormClass = self.get_model_form_class()
        if request.method == 'GET':
            # instance表示生成默認值
            form = ModelFormClass(instance=obj)
            # 渲染頁面,添加和修改能夠共用一個一個模板文件
            return render(request, 'stark/change.html', {'form': form})
        # instance = obj 表示指定給誰作修改
        form = ModelFormClass(data=request.POST, instance=obj)
        if form.is_valid():
            form.save()  # 修改數據
            # 跳轉到列表頁面
            return redirect(self.reverse_list_url())
        return render(request, 'stark/change.html', {'form': form})

    def delete_view(self, request, pk):
        """
        全部刪除頁面
        :param request:
        :param pk:
        :return:
        """
        if request.method == "GET":
            # cancel_url表示用戶點擊取消時,跳轉到列表頁面
            return render(request, 'stark/delete.html', {'cancel_url': self.reverse_list_url()})
        # 定位單條數據,並刪除!
        self.model_class.objects.filter(pk=pk).delete()
        return redirect(self.reverse_list_url())

    def wrapper(self,func):
        pass

    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
            url(r'^add/$', self.add_view, name='%s_%s_add' % info),
            url(r'^(?P<pk>\d+)/change/', self.change_view, name='%s_%s_change' % info),
            url(r'^(?P<pk>\d+)/del/', self.delete_view, name='%s_%s_del' % info),
        ]

        extra = self.extra_url()
        if extra:  # 判斷變量不爲空
            # 擴展路由
            urlpatterns.extend(extra)

        # print(urlpatterns)
        return urlpatterns

    def extra_url(self):  # 額外的路由,由調用者重構
        pass

    def reverse_list_url(self):  # 反向生成訪問列表的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_changelist' % (namespace, app_label, model_name)
        list_url = reverse(name)
        return list_url

    def reverse_add_url(self):  # 反向生成添加url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        name = '%s:%s_%s_add' % (namespace, app_label, model_name)
        add_url = reverse(name)
        return add_url

    def reverse_edit_url(self, row):  # 反向生成編輯行內容的url
        app_label = self.model_class._meta.app_label  # app名
        model_name = self.model_class._meta.model_name  # 表名
        namespace = self.site.namespace  # 命名空間
        # 拼接字符串,這裏爲change
        name = '%s:%s_%s_change' % (namespace, app_label, model_name)
        # 反向生成url,傳入參數pk=row.pk
        edit_url = reverse(name, kwargs={'pk': row.pk})
        return edit_url

    def reverse_del_url(self, row):  # 反向生成刪除行內容的url
        app_label = self.model_class._meta.app_label
        model_name = self.model_class._meta.model_name
        namespace = self.site.namespace
        # 注意:這裏爲del
        name = '%s:%s_%s_del' % (namespace, app_label, model_name)
        del_url = reverse(name, kwargs={'pk': row.pk})
        return del_url

    @property
    def urls(self):
        return self.get_urls()

class AdminSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self,model_class,stark_config=None):
        # not None的結果爲Ture
        if not stark_config:
            # 也就是說,當其餘應用調用register時,若是不指定stark_config參數
            # 那麼必然執行下面這段代碼!
            # stark_config和StarkConfig是等值的!都能實例化
            stark_config = StarkConfig

        # 添加鍵值對,實例化類StarkConfig,傳入參數model_class
        # self指的是AdminSite類
        self._registry[model_class] = stark_config(model_class,self)

        # print(self._registry)  # 打印字典
        """
        {
            app01.models.UserInfo:StarkConfig(app01.models.UserInfo)
            app02.models.Role:RoleConfig(app02.models.Role)
        }
        """

        # for k, v in self._registry.items():
        #     print(k,v)

    def get_urls(self):
        urlpatterns = []

        for k, v in self._registry.items():
            # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封裝:model_class=UserInfo,site=site對象
            # k=modes.Role,v=RoleConfig(models.Role)           # 封裝:model_class=Role,site=site對象
            app_label = k._meta.app_label
            model_name = k._meta.model_name
            urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None)))

        return urlpatterns

    @property
    def urls(self):
        # 調用get_urls方法
        # self.app_name和self.namespace值是同樣的,都是stark
        return self.get_urls(), self.app_name, self.namespace

site = AdminSite()  # 實例化類
View Code

 

進入目錄stark-->templates-->stark,建立文件delete.html

{% extends 'stark/layout.html' %}
{% block css %}


{% endblock %}
{% block content %}
    <div >
        <form method="post">
            {% csrf_token %}
            <p>是否肯定要刪除?</p>
            <a href="{{ cancel_url }}" class="btn btn-default">取消</a>
            <button type="submit" class="btn btn-danger">確 認</button>
        </form>
    </div>
{% endblock %}
View Code

 

訪問頁面: http://127.0.0.1:8000/stark/app01/depart/list/

點擊最後一條數據的刪除

提示,是否刪除

點擊取消,就會跳轉到列表頁面

點擊確認,仍是會跳轉到列表頁面,可是數據刪除了

 

6、自定義列表頁面

默認的列表頁面,它是table表格展現的。可是咱們能夠定製列表頁面,好比使用面板

進入目錄stark-->templates-->stark,建立文件custom_list.html

{% extends 'stark/layout.html' %}

{% block content %}
    <h1>自定義列表頁面</h1>
    <div class="bs-example" data-example-id="contextual-panels">
    <div class="panel panel-primary">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-success">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-info">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-warning">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-danger">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
  </div>

{% endblock %}
View Code

 

修改app01-->stark.py,重寫changelist_view方法

from stark.server.stark import site, StarkConfig
from app01 import models
from django import forms
from django.shortcuts import render

class UserInfoConfig(StarkConfig):
    list_display = ['id', 'username']


class DepartModelForm(forms.ModelForm):
    class Meta:
        model = models.Depart
        fields = "__all__"

    def clean_name(self):  # 定義鉤子
        # print(self.cleaned_data['name'])
        return self.cleaned_data['name']

class DepartConfig(StarkConfig):
    list_display = [StarkConfig.display_checkbox, 'name', 'tel', 'user', StarkConfig.display_edit_del]
    model_form_class = DepartModelForm
    # def get_add_btn(self):  # 返回None,表示不顯示添加按鈕
    #     pass
    def changelist_view(self, request):  # 重寫changelist_view方法
        # 渲染自定義的列表頁面
        return render(request,'stark/custom_list.html')

site.register(models.UserInfo, UserInfoConfig)
site.register(models.Depart, DepartConfig)
View Code

 

訪問頁面: http://127.0.0.1:8000/stark/app01/depart/list/

效果以下:

 那麼就能夠自定義列表頁面了!若是沒有重寫changelist_view方法,它顯示默認頁面

修改app01-->stark.py,註釋掉changelist_view方法

from stark.server.stark import site, StarkConfig
from app01 import models
from django import forms
from django.shortcuts import render

class UserInfoConfig(StarkConfig):
    list_display = ['id', 'username']


class DepartModelForm(forms.ModelForm):
    class Meta:
        model = models.Depart
        fields = "__all__"

    def clean_name(self):  # 定義鉤子
        # print(self.cleaned_data['name'])
        return self.cleaned_data['name']

class DepartConfig(StarkConfig):
    list_display = [StarkConfig.display_checkbox, 'name', 'tel', 'user', StarkConfig.display_edit_del]
    model_form_class = DepartModelForm
    # def get_add_btn(self):  # 返回None,表示不顯示添加按鈕
    #     pass
    # def changelist_view(self, request):  # 重寫changelist_view方法
    #     # 渲染自定義的列表頁面
    #     return render(request,'stark/custom_list.html')

site.register(models.UserInfo, UserInfoConfig)
site.register(models.Depart, DepartConfig)
View Code

刷新頁面,效果以下:

 

7、自定製URL

假設有一個表,不要增刪改功能,只要一個列表頁面,怎麼辦?

重寫get_urls方法,就能夠了

 

修改app01-->stark.py,重寫get_urls方法

from stark.server.stark import site, StarkConfig
from app01 import models
from django import forms
from django.shortcuts import render
from django.conf.urls import url

class UserInfoConfig(StarkConfig):
    list_display = ['id', 'username']


class DepartModelForm(forms.ModelForm):
    class Meta:
        model = models.Depart
        fields = "__all__"

    def clean_name(self):  # 定義鉤子
        # print(self.cleaned_data['name'])
        return self.cleaned_data['name']

class DepartConfig(StarkConfig):
    list_display = ['name', 'tel', 'user']
    # model_form_class = DepartModelForm
    def get_add_btn(self):  # 返回None,表示不顯示添加按鈕
        pass
    # def changelist_view(self, request):  # 重寫changelist_view方法
    #     # 渲染自定義的列表頁面
    #     return render(request,'stark/custom_list.html')
    def get_urls(self):
        info = self.model_class._meta.app_label, self.model_class._meta.model_name

        urlpatterns = [
            url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info),
        ]
        return urlpatterns

site.register(models.UserInfo, UserInfoConfig)
site.register(models.Depart, DepartConfig)
View Code

注意:

1. list_display裏面的字段,不能寫其餘的函數,好比編輯和刪除。由於它們依賴一些東西

2. 必需要定義get_add_btn方法。由於在changelist_view方法中,調用了get_add_btn方法

上面2個注意事項,必需要遵照,不然啓動報錯,或者頁面報錯!

 

重啓django項目,訪問頁面:

http://127.0.0.1:8000/stark/app01/depart/list/

效果以下:

訪問添加頁面:  http://127.0.0.1:8000/stark/app01/depart/add/

會報錯!

 

若是須要增肌除增刪改查之外的url,定義extra_url方法,就能夠了!

參考app02-->stark.py裏面的extra_url方法

 

總結:

1. 排序規則
    第一種方法:
        class UserInfoConfig(StarkConfig):
            order_by = ['-id']
            list_display = ['id','title',StarkConfig.display_edit,StarkConfig.display_del]

        site.register(models.UserInfo,UserInfoConfig)
    第二種方法:
        class UserInfoConfig(StarkConfig):
            list_display = ['id','title',StarkConfig.display_edit,StarkConfig.display_del]

            def get_order_by(self):
                return ['-id']
        site.register(models.UserInfo,UserInfoConfig)
2. 顯示列
    第一種方法:
        class UserInfoConfig(StarkConfig):
            list_display = ['id','title',StarkConfig.display_edit,StarkConfig.display_del]
        site.register(models.UserInfo,UserInfoConfig)
    第二種方法:
        class UserInfoConfig(StarkConfig):
            order_by = ['-id']

            def get_list_display(self):
                return  ['id','title',StarkConfig.display_edit,StarkConfig.display_del]

3. 添加按鈕
        class UserInfoConfig(StarkConfig):
            list_display = ['id','title',StarkConfig.display_edit,StarkConfig.display_del]
            def get_add_btn(self):
                # 顯示 
                # return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url())
                
                # 不顯示
                return None 
                
        site.register(models.UserInfo,UserInfoConfig)
            
4. 定製ModelForm
    第一種方法:    
        class DepartModelForm(forms.ModelForm):
            class Meta:
                model = models.Depart
                fields = "__all__"

            def clean_name(self):
                return self.cleaned_data['name']

        class DepartConfig(StarkConfig):
            list_display = [StarkConfig.display_checkbox,'id', 'name', 'tel', 'user',StarkConfig.display_edit_del]
            model_form_class = DepartModelForm
    第二種方法:    
        class DepartModelForm(forms.ModelForm):
            class Meta:
                model = models.Depart
                fields = "__all__"

            def clean_name(self):
                return self.cleaned_data['name']

        class DepartConfig(StarkConfig):
            list_display = [StarkConfig.display_checkbox,'id', 'name', 'tel', 'user',StarkConfig.display_edit_del]
            
            def get_model_form_class(self):

                return DepartModelForm

5. 自定義列表頁面
    class DepartConfig(StarkConfig):
        list_display = [StarkConfig.display_checkbox,'id', 'name', 'tel', 'user',StarkConfig.display_edit_del]
        model_form_class = DepartModelForm


        def changelist_view(self, request):
            return HttpResponse('自定義列表頁面')


    site.register(models.Depart, DepartConfig)

6. 自定製URL
    
    class RoleConfig(StarkConfig):

        order_by = ['-id', ]
        list_display = [StarkConfig.display_checkbox,'id','title']


        def get_add_btn(self):
            return False
        
        def extra_url(self):
            data = [
                url(r'^xxxxxxx/$', self.xxxxxx),
            ]

            return data

        def xxxxxx(self,request):
            print('....')

            return HttpResponse('xxxxx')


        def get_urls(self):
            info = self.model_class._meta.app_label, self.model_class._meta.model_name

            urlpatterns = [
                url(r'^list/$', self.wrapper(self.changelist_view), name='%s_%s_changelist' % info),
            ]

            extra = self.extra_url()
            if extra:
                urlpatterns.extend(extra)

            return urlpatterns

    site.register(models.Role,RoleConfig)

7. 增長URL(除了增刪改查之外的url)
    class RoleConfig(StarkConfig):
        order_by = ['-id']  # 有負號,表示降序
        # 定義顯示的列
        list_display = [StarkConfig.display_checkbox,'id','title']
        
        def sk2(self, request):
            return HttpResponse('sk2神仙水')
    
        def extra_url(self):
            data = [
                url(r'^sk2/$', self.sk2),
            ]
            return data
    
    site.register(models.Role,RoleConfig)  # 註冊表
View Code

 

完整代碼,請參考github:

https://github.com/987334176/luffy_stark/archive/v1.1.zip

相關文章
相關標籤/搜索