程序啓動時查找全部註冊了的apps.py 會執行def ready方法
MyAdmin.apps.py:
def ready(self):
super(MyadminConfig,self).ready()html
from django.utils.module_loading import autodiscover_modules
autodiscover_modules('reg')
這裏應該是收集全部的reg文件。執行reg.py中的註冊函數
app01.reg.py:
from app01 import models
from MyAdmin.service import v1
#執行v1.site.register方法,將model_class傳入
v1.site.register(models.UserInfo)
v1.site.register(models.Role)
MyAdmin.service.v1.py:
#site爲MySite對象
site = MySite()
#經過執行並傳入model的register函數,生成一個字典並保存:
ret={
"UserInfo":BaseAdmin(UserInfo,site)
"Role":BaseAdmin(Role,site)
}
def register(self,model_class,xxx = BaseAdmin):
self._registry[model_class] = xxx(model_class,self)
Django.urls.py:
from django.conf.urls import url
from MyAdmin.service import v1
urlpatterns = [
url(r'^md/', v1.site.urls),
]
當Django啓動後,這裏使用路由分發的原理 v1.site.urls 分發了預設的url以及
根據app名稱跟類名拼接生成的url,在此基礎上再次分發,使每一個類都有
4個url:changelist、add、delete、change
MyAdmin.service.v1.py class python
@property 1. def urls(self): return self.get_urls(),self.app_name,self.namespace 2. def get_urls(self): from django.conf.urls import url,include ret = [ url(r'^login/',self.login,name='login'), url(r'^logout/',self.login,name='logout'), ] """ model_cls爲models類,admin_obj爲BaseAdmin(model類, MySite()即site ),即傳入2個參數的BaseAdmin對象, admin_obj.urls則執行BaseAdmin的urls方法 """ for model_cls,admin_obj in self._registry.items(): app_label = model_cls._meta.app_label model_name = model_cls._meta.model_name ret.append(url(r'^%s/%s' % (app_label,model_name),include(admin_obj.urls))) return ret 3.@property def urls(self): from django.conf.urls import url,include info = self.model_class._meta.app_label,self.model_class._meta.model_name """
這裏的self.model_class爲以前傳入的model類,因此同樣能夠取得app和model類名,由此設置別名,
方便後續反向生成url.
"""
urlpatterns = [
url(r'^$',self.changelist_view,name='%s_%s_changelist' % info),
url(r'^add/$',self.add_view,name='%s_%s_add' % info),
url(r'^(.+)/delete/$',self.delete_view,name='%s_%s_delete' % info),
url(r'^(.+)/change/$',self.change_view,name='%s_%s_change' % info),
]
return urlpatternssql
生成url後,咱們須要對每一個url指定不一樣的操做,以changelist爲例子,每一個類定義的字段,以及字段名都不一樣,咱們又不可能爲每個類的url作單獨的模版,假若有幾十個類,這樣增刪改查工做量太大,所以咱們須要爲每一個類的增刪改查作統一的視圖模版.django
階段一代碼:session
1.目錄結構:app
2.代碼:ide
1 from django.http import HttpResponse 2 from django.shortcuts import render 3 4 class BaseAdmin(object): 5 list_display = "__all__" 6 7 def __init__(self,model_class,site): 8 self.model_class = model_class 9 self.site = site 10 self.request = None 11 12 @property 13 def urls(self): 14 from django.conf.urls import url 15 """ 16 這裏的self.model_class爲以前傳入的model類,因此同樣能夠取得app和model類名,由此設置別名, 17 方便後續反向生成url. 18 """ 19 info = self.model_class._meta.app_label,self.model_class._meta.model_name 20 urlpatterns = [ 21 url(r'^$',self.changelist_view,name='%s_%s_changelist' % info), 22 url(r'^add/$',self.add_view,name='%s_%s_add' % info), 23 url(r'^(.+)/delete/$',self.delete_view,name='%s_%s_delete' % info), 24 url(r'^(.+)/change/$',self.change_view,name='%s_%s_change' % info), 25 ] 26 return urlpatterns 27 28 def add_view(self,request): 29 """ 30 新增數據 31 :param request: 32 :return: 33 """ 34 info = self.model_class._meta.app_label,self.model_class._meta.model_name 35 data = "%s_%s_add" % info 36 return HttpResponse(data) 37 38 def delete_view(self,request,pk): 39 """ 40 刪除數據 41 :param request: 42 :return: 43 """ 44 # self.model_class.objects.filter(id=pk).delete() 45 info = self.model_class._meta.app_label, self.model_class._meta.model_name 46 data = "%s_%s_del" % info 47 return HttpResponse(data) 48 49 def change_view(self,request,pk): 50 """ 51 修改數據 52 :param request: 53 :return: 54 """ 55 info = self.model_class._meta.app_label, self.model_class._meta.model_name 56 data = "%s_%s_change" % info 57 return HttpResponse(data) 58 59 def changelist_view(self,request): 60 """ 61 查看列表 62 :param request: 63 :return: 64 """ 65 self.request = request 66 result_list = self.model_class.objects.all() 67 context = { 68 'result_list':result_list, 69 'list_display':self.list_display, 70 'admin_obj':self #此處self爲自定製的Admin-models類對象 71 } 72 return render(request,'md/change_list.html',context) 73 74 75 class MySite(object): 76 def __init__(self): 77 self._registry = {} 78 self.namespace = 'MyAdmin' 79 self.app_name = 'MyAdmin' 80 81 def register(self,model_class,xxx = BaseAdmin): 82 self._registry[model_class] = xxx(model_class,self) 83 """{ 84 modle類:BaseAdmin(model類, MySite()即site ) 85 } 86 """ 87 88 def get_urls(self): 89 from django.conf.urls import url,include 90 ret = [ 91 url(r'^login/',self.login,name='login'), 92 url(r'^logout/',self.login,name='logout'), 93 ] 94 #經過循環items得到每個model類所在的app名,以及小寫的類名 95 for model_cls,admin_obj in self._registry.items(): 96 """ 97 model_cls爲models類,admin_obj爲BaseAdmin(model類, MySite()即site ),即傳入2個參數的BaseAdmin對象, 98 admin_obj.urls則執行BaseAdmin的urls方法 99 """ 100 app_label = model_cls._meta.app_label 101 model_name = model_cls._meta.model_name 102 # print(app_label,model_name) 103 #拼接生成url,如/md/app01/userinfo/,再次分發拿到最終的/md/app01/userinfo/change_list等url 104 ret.append(url(r'^%s/%s' % (app_label,model_name),include(admin_obj.urls))) 105 106 return ret 107 108 @property 109 def urls(self): 110 return self.get_urls(),self.app_name,self.namespace 111 112 def login(self,request): 113 return HttpResponse('login') 114 115 site = MySite()
MyAdmin.templates.md.change_list.html:函數
1 {% load md_list %} 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <meta charset="UTF-8"> 6 <title>Title</title> 7 </head> 8 <body> 9 <h1>數據列表</h1> 10 {% func result_list list_display admin_obj%} 11 </body> 12 </html>
MyAdmin.templates.md.md.html:ui
1 <table border="1"> 2 <thead> 3 4 </thead> 5 <tbody> 6 {% for item in res %} 7 <tr> 8 {% for val in item %} 9 <td>{{ val }}</td> 10 {% endfor %} 11 </tr> 12 {% endfor %} 13 </tbody> 14 </table>
MyAdmin.templatetags.md_list.py:this
from django.template import Library from types import FunctionType register = Library() def table_body(result_list,list_display,admin_obj): """ 循環自定製的列表,生成對應的標籤數據 :param result_list: 數據表全部數據 :param list_display: 自定製列表 ['id','name',fun] :param admin_obj: 繼承自BaseAdmin的models類對象,如:AdminUserInfo() :return: """ for row in result_list: yield [name(admin_obj,row) if isinstance(name,FunctionType) else getattr(row,name) for name in list_display] @register.inclusion_tag("md/md.html") def func(result_list,list_dispaly,admin_obj): """ inclusion_tag,調用這個tag的模版,首先會將數據交給md.html根據html渲染出標籤, 而後替換到調用這個tag的位置。 :param result_list: :param list_dispaly: :param admin_obj: :return: """ v = table_body(result_list,list_dispaly,admin_obj) return {'res':v}
MyAdmin.apps.py:
from django.apps import AppConfig class MyadminConfig(AppConfig): name = 'MyAdmin' def ready(self): super(MyadminConfig,self).ready() from django.utils.module_loading import autodiscover_modules autodiscover_modules('reg')
app01.reg.py:
from app01 import models from MyAdmin.service import v1 from django.utils.safestring import mark_safe class AdminUserInfo(v1.BaseAdmin): def func(self,obj): """ 反向生成url,使每一條數據能夠跳轉到詳細頁執行change視圖 :param obj: 數據錶行數據 :return: 編輯按鈕跳轉url """ from django.urls import reverse #反向生成url,須要namespace,app跟類名稱在註冊時傳入 name = "{0}:{1}_{2}_change".format(self.site.namespace,self.model_class._meta.app_label,self.model_class._meta.model_name) #obj爲查詢出的數據表每一行數據 url = reverse(name, args=(obj.pk,)) return mark_safe("<a href='{0}'>編輯</a>".format(url)) def checkbox(self,obj): """ 生成checkbox標籤 :param obj: 行數據 :return: 帶有數據行id的checkbox標籤 """ tag = "<input type='checkbox' value='{0}' />".format(obj.pk) return mark_safe(tag) list_display = [checkbox,'id','username',func] """ 這裏註冊後,self._registry[model_class] = xxx(model_class,self) 原來的字典就變爲{UserInfo:AdminUserInfo(UserInfo,site)}, 所以傳過去的context字典中的admin_obj再也不是BaseAdmin對象,而是這裏的AdminUserInfo對象,它除了能繼承 BaseAdmin類的各類方法,還有本身定製的func 以及checkbox方法. """ v1.site.register(models.UserInfo,AdminUserInfo) class AdminRole(v1.BaseAdmin): list_display = ['id', 'name'] v1.site.register(models.Role,AdminRole)
settings配置文件:
1 """ 2 Django settings for Admin自定製 project. 3 4 Generated by 'django-admin startproject' using Django 1.11.2. 5 6 For more information on this file, see 7 https://docs.djangoproject.com/en/1.11/topics/settings/ 8 9 For the full list of settings and their values, see 10 https://docs.djangoproject.com/en/1.11/ref/settings/ 11 """ 12 13 import os 14 15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 18 19 # Quick-start development settings - unsuitable for production 20 # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 21 22 # SECURITY WARNING: keep the secret key used in production secret! 23 SECRET_KEY = '@bfz%(znqs&m2907_q0ck%ly2=ghs^p@nptcwdrr^333vw%xl9' 24 25 # SECURITY WARNING: don't run with debug turned on in production! 26 DEBUG = True 27 28 ALLOWED_HOSTS = [] 29 30 31 # Application definition 32 33 INSTALLED_APPS = [ 34 # 'django.contrib.admin', 35 # 'django.contrib.auth', 36 'django.contrib.contenttypes', 37 'django.contrib.sessions', 38 # 'django.contrib.messages', 39 'django.contrib.staticfiles', 40 'app01', 41 'MyAdmin.apps.MyadminConfig' 42 ] 43 44 MIDDLEWARE = [ 45 'django.middleware.security.SecurityMiddleware', 46 'django.contrib.sessions.middleware.SessionMiddleware', 47 'django.middleware.common.CommonMiddleware', 48 'django.middleware.csrf.CsrfViewMiddleware', 49 # 'django.contrib.auth.middleware.AuthenticationMiddleware', 50 # 'django.contrib.messages.middleware.MessageMiddleware', 51 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 ] 53 54 ROOT_URLCONF = 'Admin自定製.urls' 55 56 TEMPLATES = [ 57 { 58 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 'DIRS': [os.path.join(BASE_DIR, 'templates')] 60 , 61 'APP_DIRS': True, 62 'OPTIONS': { 63 'context_processors': [ 64 'django.template.context_processors.debug', 65 'django.template.context_processors.request', 66 # 'django.contrib.auth.context_processors.auth', 67 # 'django.contrib.messages.context_processors.messages', 68 ], 69 }, 70 }, 71 ] 72 73 WSGI_APPLICATION = 'Admin自定製.wsgi.application' 74 75 76 # Database 77 # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 78 79 DATABASES = { 80 'default': { 81 'ENGINE': 'django.db.backends.sqlite3', 82 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 83 } 84 } 85 86 87 # Password validation 88 # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 89 90 AUTH_PASSWORD_VALIDATORS = [ 91 # { 92 # 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 93 # }, 94 # { 95 # 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 96 # }, 97 # { 98 # 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 99 # }, 100 # { 101 # 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 102 # }, 103 ] 104 105 106 # Internationalization 107 # https://docs.djangoproject.com/en/1.11/topics/i18n/ 108 109 LANGUAGE_CODE = 'en-us' 110 111 TIME_ZONE = 'UTC' 112 113 USE_I18N = True 114 115 USE_L10N = True 116 117 USE_TZ = True 118 119 120 # Static files (CSS, JavaScript, Images) 121 # https://docs.djangoproject.com/en/1.11/howto/static-files/ 122 123 STATIC_URL = '/static/'