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.service.v1

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/\'
Settings

 

以上是关于Django防Admin定制插件的主要内容,如果未能解决你的问题,请参考以下文章

django自定制Admin

Django admin 设置和定制

django1.6 admin不能登录

Django之admin

Django基础,Day8 - 管理后台定制显示

如何在 Django admin 中向第三方外部 jQuery 插件提供 $