一、装饰器
装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。
基本装饰器
不应用装饰器
def wrapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner def f1():
print('f1') print(f1.__name__)
执行输出:
f1
使用装饰器
def wrapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner @wrapper
def f1():
print('f1') print(f1.__name__)
执行输出:
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__)
执行输出:
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() # 实例化类
修改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) # 注册表
添加数据
使用navicat打开app02_role表,添加2条数据
打开app01_userinfo表,添加2条数据
访问页面
http://127.0.0.1:8000/stark/app02/role/list/
效果如下:
查看Pycharm控制台输出:
<class 'app02.models.Role'>
<QuerySet [<Role: Role object>, <Role: Role object>]>
应该有一个页面,要展示一下数据。那么页面,应该写在哪里?
要写在stark里面,因为它是组件,它是能够应用到其他django项目的!
前端展示数据
进入stark应用目录,创建目录templates,在此目录下创建stark目录。在此目录创建layout.html。这个是母版文件!
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路飞学城</title>
<link rel="shortcut icon" href="{% static 'stark/imgs/luffy-study-logo.png' %} ">
<link rel="stylesheet" href="{% static 'stark/plugins/bootstrap/css/bootstrap.css' %} "/>
<link rel="stylesheet" href="{% static 'stark/plugins/font-awesome/css/font-awesome.css' %} "/>
<link rel="stylesheet" href="{% static 'stark/css/commons.css' %} "/>
<link rel="stylesheet" href="{% static 'stark/css/nav.css' %} "/>
<style>
body {
margin: 0;
} .no-radius {
border-radius: 0;
} .no-margin {
margin: 0;
} .pg-body > .left-menu {
background-color: #EAEDF1;
position: absolute;
left: 0;
top: 48px;
bottom: 0;
width: 220px;
border: 1px solid #EAEDF1;
overflow: auto;
} .pg-body > .right-body {
position: absolute;
left: 225px;
right: 0;
top: 48px;
bottom: 0;
overflow: scroll;
border: 1px solid #ddd;
border-top: 0;
font-size: 13px;
min-width: 755px;
} .navbar-right {
float: right !important;
margin-right: -15px;
} .luffy-container {
padding: 15px;
} </style>
{% block css %}{% endblock %}
</head>
<body> <div class="pg-header">
<div class="nav">
<div class="logo-area left">
<a href="#">
<img class="logo" src="{% static 'stark/imgs/logo.svg' %}">
<span style="font-size: 18px;">路飞学城 </span>
</a>
</div> <div class="left-menu left">
<a class="menu-item">资产管理</a>
<a class="menu-item">用户信息</a>
<a class="menu-item">路飞管理</a>
<div class="menu-item">
<span>使用说明</span>
<i class="fa fa-caret-down" aria-hidden="true"></i>
<div class="more-info">
<a href="#" class="more-item">管他什么菜单</a>
<a href="#" class="more-item">实在是编不了</a>
</div>
</div>
</div> <div class="right-menu right clearfix"> <div class="user-info right">
<a href="#" class="avatar">
<img class="img-circle" src="{% static 'stark/imgs/default.png' %}">
</a> <div class="more-info">
<a href="#" class="more-item">个人信息</a>
<a href="/logout/" class="more-item">注销</a>
</div>
</div> <a class="user-menu right">
消息
<i class="fa fa-commenting-o" aria-hidden="true"></i>
<span class="badge bg-success">2</span>
</a> <a class="user-menu right">
通知
<i class="fa fa-envelope-o" aria-hidden="true"></i>
<span class="badge bg-success">2</span>
</a> <a class="user-menu right">
任务
<i class="fa fa-bell-o" aria-hidden="true"></i>
<span class="badge bg-danger">4</span>
</a>
</div> </div>
</div>
<div class="pg-body">
<div class="left-menu">
<div class="menu-body"> </div>
</div>
<div class="right-body">
<div> </div>
{% block content %} {% endblock %}
</div>
</div> <script src="{% static 'stark/js/jquery-3.3.1.min.js' %} "></script>
<script src="{% static 'stark/plugins/bootstrap/js/bootstrap.js' %} "></script>
{% block js %} {% endblock %}
</body>
</html>
进入目录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 %}
进入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
注意: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() # 实例化类
重启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() # 实例化类
修改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 %}
刷新页面,效果如下:
去掉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() # 实例化类
修改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) # 注册表
刷新页面,效果同上!
修改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)
访问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() # 实例化类
修改 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
修改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
刷新页面,效果如下:
注意:在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) # 注册表
注意: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
使用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)
访问部门的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)
千万要记得在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)
修改 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() # 实例化类
修改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)
访问页面: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)
刷新页面,效果如下:
但是有一个问题,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() # 实例化类
修改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)
刷新页面,效果如下:
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() # 实例化类
修改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)
刷新页面,效果同上!
修改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) # 注册表
访问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() # 实例化类
修改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)
重启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() # 实例化类
刷新页面,效果如下:
编辑和删除,占用太宽了。合并成一列!
修改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() # 实例化类
修改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)
刷新页面,效果如下:
通过这样,想显示 编辑、删除、编辑和删除。都可以任意选择!
但是有一个问题,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() # 实例化类
重启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() # 实例化类
刷新页面,效果如下:
点击删除按钮,会自动跳转页面
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 %}
访问页面: 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() # 实例化类
修改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)
修改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 %}
刷新页面,就没有添加按钮了,效果如下:
那么其他页面,是有的,访问页面:
但是链接不对,得生成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() # 实例化类
访问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() # 实例化类
进入目录 stark-->templates-->stark,创建文件change.html
写一个form表单,使用for循环
{% extends 'stark/layout.html' %}
{% block css %}
<style>
.change input,select {
display: block;
width: 100%;
height: 34px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
</style> {% endblock %}
{% block content %}
<div style="width: 680px;margin: 0 auto;">
<form class="change" method="post">
{% csrf_token %}
{% for filed in form %}
<div class="form-group">
<label>{{ filed.label }}</label>
{{ filed }}
{{ filed.errors.0 }}
</div>
{% endfor %} <button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
{% endblock %}
修改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)
重启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() # 实例化类
重启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() # 实例化类
测试添加功能,访问以下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)
访问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() # 实例化类
注意:添加和编辑,可以共用一个模板文件。因为它们都是用的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() # 实例化类
进入目录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 %}
访问页面: 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 %}
修改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)
访问页面: 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)
刷新页面,效果如下:
七、自定制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)
注意:
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) # 注册表
完整代码,请参考github: