裝飾器本質上就是一個python函數,他可讓其餘函數在不須要作任何代碼變更的前提下,增長額外的功能,裝飾器的返回值也是一個函數對象。css
裝飾器的應用場景:好比插入日誌,性能測試,事務處理,緩存等等場景。html
不該用裝飾器前端
def wrapper(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner def f1(): print('f1') print(f1.__name__)
執行輸出:python
f1
使用裝飾器jquery
def wrapper(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner @wrapper def f1(): print('f1') print(f1.__name__)
執行輸出:git
inner
咦?爲何輸出了inner,我要的是f1啊。由於函數裝飾以後,至關於執行了inner函數,因此輸出innergithub
爲了解決這個問題,須要調用一個模塊wrapsweb
wraps將 被修飾的函數(wrapped) 的一些屬性值賦值給 修飾器函數(wrapper) ,最終讓屬性的顯示更符合咱們的直覺!sql
導入模塊functools,並使用@functools.wraps,就可進行高級假裝數據庫
import functools def wrapper(func): @functools.wraps(func) def inner(*args,**kwargs): return func(*args,**kwargs) return inner @wrapper def f1(): print('f1') print(f1.__name__)
執行輸出:
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,也就是複選框
修改 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/
點擊添加按鈕,頁面跳轉
那麼頁面的添加按鈕,連接是不同的。
問題來了,若是是添加,這個頁面應該有幾個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)
刷新頁面,效果以下:
假設有一個表,不要增刪改功能,只要一個列表頁面,怎麼辦?
重寫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: