Django防Admin定制插件
Posted Mitsuis
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django防Admin定制插件相关的知识,希望对你有一定的参考价值。
程序启动时查找所有注册了的apps.py 会执行def ready方法
MyAdmin.apps.py:
def ready(self):
super(MyadminConfig,self).ready()
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
@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 urlpatterns
生成url后,我们需要对每个url指定不同的操作,以changelist为例子,每个类定义的字段,以及字段名都不同,我们又不可能为每一个类的url做单独的模版,假如有几十个类,这样增删改查工作量太大,因此我们需要为每个类的增删改查做统一的视图模版.
阶段一代码:
1.目录结构:
2.代码:
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:
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:
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/\'
以上是关于Django防Admin定制插件的主要内容,如果未能解决你的问题,请参考以下文章