zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    87 求先序排列
    iOS App用WKWebView加载h5, h5多页面手势返回,h5返回App
    H5判断是手机端浏览器or原生App Webview
    vue-router笔记
    我的博客园页面定制 CSS 代码
    用swiper实现不规则分页滚动 & 给分页器加颜色
    Angular1.6.9 选择本地文件上传后台
    Vue移动端上拉加载更多实现请求分页数据
    导航折叠菜单
    类似于Flipboard页面翻折效果
  • 原文地址:https://www.cnblogs.com/mitsui/p/7492421.html
Copyright © 2011-2022 走看看