• python 全栈开发,Day114(装饰器,排序规则,显示列,添加按钮,定制ModelForm,自定义列表页面,自定制URL)


    一、装饰器

    装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

    装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

    基本装饰器

    不应用装饰器

    def wrapper(func):
        def inner(*args,**kwargs):
            return func(*args,**kwargs)
        return inner
    
    def f1():
        print('f1')
    
    print(f1.__name__)
    View Code

    执行输出:

    f1

    使用装饰器

    def wrapper(func):
        def inner(*args,**kwargs):
            return func(*args,**kwargs)
        return inner
    
    @wrapper
    def f1():
        print('f1')
    
    print(f1.__name__)
    View Code

    执行输出:

    inner

    咦?为什么输出了inner,我要的是f1啊。因为函数装饰之后,相当于执行了inner函数,所以输出inner

    为了解决这个问题,需要调用一个模块wraps

    高级装饰器

    wraps将 被修饰的函数(wrapped) 的一些属性值赋值给 修饰器函数(wrapper) ,最终让属性的显示更符合我们的直觉!

    导入模块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会用到

    二、排序规则

    务必下载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;
                 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- 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/

    效果如下:

    二、显示列

    如果需要显示自定义的列,怎么做?

    定义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,发现代码都写在这里了。可读性不好!

    如果要增加其他功能呢?比如下面的效果:

    那么就需要拆分代码,不同的功能,放在不同的方法里面!

    四、添加按钮

    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/

    点击添加按钮,页面跳转

    那么页面的添加按钮,链接是不一样的。

    五、定制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;
                 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=" 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/

    点击最后一条数据的删除

    提示,是否删除

    点击取消,就会跳转到列表页面

    点击确认,还是会跳转到列表页面,但是数据删除了

    六、自定义列表页面

    默认的列表页面,它是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

    刷新页面,效果如下:

    七、自定制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

  • 相关阅读:
    (三十四)在所有的添加方法上记录一下(添加操作)
    (三十三)订单管理-修改订单状态
    (三十二)订单管理-查询订单详情
    (三十一)订单管理-查询订单
    (三十)商品管理-添加商品(上传图片)
    1.python的安装
    require(): open_basedir restriction in effect. File(/www/wwwroot/xcx/zerg/thinkphp/start.php) is not within the allowed path(s): (/www/wwwroot/xcx/zerg/public/:/tmp/:/proc/) in /www/wwwroot/xcx/zerg/p
    phpstorm-xdebug的安装
    swoole在线聊天学习笔记
    18.swoole学习笔记--案例
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9562898.html
Copyright © 2020-2023  润新知