Django仿Admin定製插件(一)

程序啓動時查找全部註冊了的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.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: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/'
Settings
相關文章
相關標籤/搜索