zoukankan      html  css  js  c++  java
  • django----admin源码流程

    Admin源码分析 

    1、启动 python manage.py runserver 时候,会自动执行每一个 app 下的 admin.py

     

    2、注册模型(执行每一个app下的admin.py 文件)

    3、设计url  

     将AdminSite实例挂载到指定的URLconfig中

    admin.site.urls  目的是动态生成 一系列 url 将他们添加到 urlpatterns 中(后面有分析)

    对 AdminSite 类分析

    每一个模型都可以指定一个ModelAdmin ,封装了该模型的特定的管理功能

     本质上实例化的是AdminSite()   

     一部分AdmainSite 源码

    class AdminSite:
        def __init__(self, name='admin'):  
            self._registry = {}  # AdminSite 初始化一个空字典 
            self.name = name
            self._actions = {'delete_selected': actions.delete_selected}
            self._global_actions = self._actions.copy()
            all_sites.add(self)
        def register(self, model_or_iterable, admin_class=None, **options):   #用来注册
            admin_class = admin_class or ModelAdmin   
            if isinstance(model_or_iterable, ModelBase):
                model_or_iterable = [model_or_iterable]
            for model in model_or_iterable:
                if model._meta.abstract:
                    raise ImproperlyConfigured(
                        'The model %s is abstract, so it cannot be registered with admin.' % model.__name__
                    )
                if model in self._registry:
                    raise AlreadyRegistered('The model %s is already registered' % model.__name__)
                if not model._meta.swapped:
                    if options:                    # options 指的是UserAdmin,看是否用户自定制了admin,  admin.site.register(models.UserInfo, UserAdmin)
                        options['__module__'] = __name__
                        admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
                    self._registry[model] = admin_class(model, self)
    

      

    admin.site.urls   中的 urls 属性

    admin.site.urls  返回的是一个元祖 元祖的第一个参数是一个列表 由 get_urls()  返回

    get_urls() 的目的为了将app_name 和 model_name 动态添加到 urlpatterns = [] 里面  (包括所有的url,例如 <URLPattern 'logout/' [name='logout']>等 login)

    class AdminSite:
        @property
        def urls(self):
            return self.get_urls(), 'admin', self.name
        def get_urls(self):
            from django.urls import include, path, re_path
            from django.contrib.contenttypes import views as contenttype_views
            def wrap(view, cacheable=False):
                def wrapper(*args, **kwargs):
                    return self.admin_view(view, cacheable)(*args, **kwargs)
                wrapper.admin_site = self
                return update_wrapper(wrapper, view)
            urlpatterns = [
                path('', wrap(self.index), name='index'),
                path('login/', self.login, name='login'),
                path('logout/', wrap(self.logout), name='logout'),
                path('password_change/', wrap(self.password_change, cacheable=True), name='password_change'),
                path(
                    'password_change/done/',
                    wrap(self.password_change_done, cacheable=True),
                    name='password_change_done',
                ),
                path('jsi18n/', wrap(self.i18n_javascript, cacheable=True), name='jsi18n'),
                path(
                    'r/<int:content_type_id>/<path:object_id>/',
                    wrap(contenttype_views.shortcut),
                    name='view_on_site',
                ),
            ]
            valid_app_labels = []
            for model, model_admin in self._registry.items():
                urlpatterns += [
                    path('%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)),
                ]
                if model._meta.app_label not in valid_app_labels:
                    valid_app_labels.append(model._meta.app_label)
            if valid_app_labels:
                regex = r'^(?P<app_label>' + '|'.join(valid_app_labels) + ')/$'   
                urlpatterns += [
                    re_path(regex, wrap(self.app_index), name='app_list'),
                ]
            return urlpatterns

    超级简单模拟    admin.site.urls

    高级操作。类似Django中的admin.site.urls  

    admin.site.urls的本质:它读取_registry所有字典里面的数据,为字典里面的每一个类生成了4个url

    from django.shortcuts import render,HttpResponse
    from django.contrib import admin
    from django.urls import path,re_path
    
    def login(request):
        return HttpResponse("ok")
    
    def change_list(request):
        return HttpResponse("列表页面")
    
    def add_view(request):
        return HttpResponse("添加页面")
    
    def change_view(request,nid):
        return HttpResponse("修改页面")
    
    def delete_view(request,nid):
        return HttpResponse("删除页面")
    def test(req):
        return HttpResponse('test')
    def index(request):
        return HttpResponse("index")
    class AdminSite:
        def __init__(self, name='admin'):
            self.name = name
        @property
        def urls(self):
            print("zhxign")
            urlpatterns = [
                path('',index),   #相当于 admin "http://127.0.0.1:8000/admin/"
                path('login',login)
            ]
            for model_class, v in admin.site._registry.items():
                print(model_class)                       # 打印的是每一个类<class 'app01.models.UserInfo'>
                cls_name = model_class._meta.model_name  # 当前类名称的小写
                app_name = model_class._meta.app_label   # 当前app的名称
                urls_list = re_path(r'^{0}/{1}/$'.format(app_name, cls_name), change_list, name="login")
                urlpatterns.append(urls_list)                                          #查
                add_url = re_path(r'^{0}/{1}/add/$'.format(app_name, cls_name), add_view, name="login")                 #增
                urlpatterns.append(add_url)
    
                change_url = re_path(r'^{0}/{1}/(d+)/change/$'.format(app_name, cls_name), change_view, name="login")  #改
                urlpatterns.append(change_url)
    
                del_url = re_path(r'^{0}/{1}/(d+)/del/$'.format(app_name, cls_name), delete_view, name="login")        #删
                urlpatterns.append(del_url)
            return urlpatterns,"admin",self.name
    site = AdminSite()
    

     

    补充:利用include 做分发url 功能 

    include函数的返回值     return (urlconf_module, app_name, namespace)  为一个数组

    如果不使用 include

    urlpatterns = [
        re_path(r'admin/', admin.site.urls),
        path('index/',([
            path('', views.index),
            path('login', views.login)
        ],None,None)),
    ]
    

    include的本质就是:返回了一个元组,元组的第一个是这个模块

    include里面

      既可以写一个列表include([]),利用include做分发

      也可以返回一个字符串:帮我们去找到这个模块,找到所有的映射关系

    总结

    - admin源码流程
            a. 运行程序,找到每一个app中的 admin.py 文件,并加载
                - app01.admin.py 
                    - 创建admin.site中的对象
                    - 执行对象的 register方法,目的:将注册类添加到 _registry中 
                        _registry = {  
                            key是传进来的model   value:是ModelAdmin的对象,传了两个参数
                            models.Role: ModelAdmin(models.Role,admin.site),
                            models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
                            models.UserType: ModelAdmin(models.UserType,admin.site)
                        }
                    
                - app02.admin.py
                    - 用app01.admin中创建那个admin.site对象
                    - 执行对象的 register方法,目的:讲注册类添加到 _registry中 
                        _registry = {
                            models.Role: ModelAdmin(models.Role,admin.site),
                            models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
                            models.UserType: ModelAdmin(models.UserType,admin.site)
                            models.Article: ModelAdmin(models.Article,admin.site)
                        }
            
                admin.site是一个对象(单例模式创建),其中封装了: 
                    _registry = {
                        models.Role: ModelAdmin(models.Role,admin.site),
                        models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
                        models.UserType: ModelAdmin(models.UserType,admin.site)
                        models.Article: ModelAdmin(models.Article,admin.site)
                    }
            b. urls.py 
                再次调用 admin.site 对象的 urls属性:
                    urlpatterns = [
                        url(r'^admin/', admin.site.urls),
                    ]
                
                class ModelAdmin(object):
                    def __init__(self,model_class,site):
                        self.model_class = model_class
                        self.site = site 
                        
                    def changelist_view(self,request):
                        data_list = self.model_class.objects.all()   #是动态的
                        return HttpResponse('列表页面')
    
                    def add_view(self,request):
                        return HttpResponse('添加页面')
    
    
                    def delete_view(self,request,nid):
                        return HttpResponse('删除页面')
    
                    def change_view(self,request,nid):
                        return HttpResponse('修改页面')
                    
                    def get_urls(self):
                         urlpatterns = [
                            url(r'^$', self.changelist_view),
                            url(r'^add/$', self.add_view),
                            url(r'^(.+)/delete/$', self.delete_view),
                            url(r'^(.+)/change/$', self.change_view),
                        ]
                        return urlpatterns
                    
                    @property 
                    def urls(self):
                        return self.get_urls()
                    
                
                class AdminSite(object):
                    def __init__(self):
                        self._registry = {}
                        
                    def register(self,model_class,model_admin):
                        self._registry[model_class] = model_admin(model_class,self)
                    
                    def get_urls(self):
                        """
                        models.Role: ModelAdmin(models.Role,admin.site),
                        models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
                        models.UserType: ModelAdmin(models.UserType,admin.site)
                        models.Article: ModelAdmin(models.Article,admin.site)
                        """
                        url_list = []
                        for model_class,model_admin in self._registry.items():      #利用利用之前已经注册的_registry,动态生成一系列 url,添加到路由中
                            model_class是一个类
                            app_name = model_class._meta.app_label
                            model_name = model_class._meta.model_name 
                            url_list += [
                                url('%s/%s' %(app_name,model_name,), include(model_admin.urls))
                            ]
                            
                        return url_list
                            
                    
                    @property
                    def urls(self):
                        return (self.get_urls(), None,None )
    

      




  • 相关阅读:

    20145309《网络对抗》网络欺诈技术防范
    ceshi
    20145306 网路攻防 web安全基础实践
    20145306 张文锦 网络攻防 web基础
    20145306张文锦 网络欺诈技术防范
    20145306 《网络攻防》 信息搜集与漏洞扫描
    20145306 《网络攻防》 MSF基础应用
    20145306张文锦《网络对抗》恶意代码分析
    20145306 《网络攻防》 免杀技术
  • 原文地址:https://www.cnblogs.com/yanxiaoge/p/10628160.html
Copyright © 2011-2022 走看看