• Django admin组件源码流程


     admin 组件

      Django 自带的用户后台组件

      用于用户便携的操作

    admin 组件核心

    • 启动
    • 注册
    • 设计url

    启动核心代码

      每个app 通过 apps.py 扫描 admin.py 文件 并执行

    """
    setting.py 
    
    setting.py 中会对注册的 app 自动加载各自里面的 AppxxConfig 模块
    """ 
    INSTALLED_APPS = [
        ...
        'app01.apps.App01Config',
        'app02.apps.App02Config',
    ]
    """
    apps.py
    
    app下的里面的 adminConfig 在自动执行的时候可以进行启动操作
    """
    from django.apps import AppConfig
    class App01Config(AppConfig):
        name = 'app01'
    """
    admin 源码 
    
    调用每个app 下的admin.py 文件进行执行
    """
    import admin
            # 执行每一个app下的admin.py文件
            autodiscover_modules('admin', register_to=site)
    """
    admin.py
    
    被执行的 admin.py 文件
    """
    from django.contrib import admin
    from rbac.models import *
    # Register your models here.

     注册核心代码

       在admin.py 文件中对表进行注册

      注册后的表要判断是否有自定义的配置文件

      若没有则使用默认的 Modeladmin

    """
    admin 注册流程核心源码
    """
    class AdminSite(object):
        def __init__(self,name="admin"):
            # 定义一个空字典用于保存注册
            self._registry={}
            
        # 注册函数
        # 需要有两个参数, 被注册的表 以及 是否有自定义的配置操作
        def register(self, model, admin_class=None, **options):
            # 首先对是否存在自定义配置操作进行判断
            if not admin_class:
                # 如果无自定义则用默认的
                admin_class = Modeladmin
            # 有自己的就用自己的
            # 注意这里的键为类名而不是字符串 
            self._registry[model] = admin_class(model, self) 
                # {Book:ModelAdmin(Book),Publi sh:ModelAdmin(Publish)}
    
    # 进行实例化实现单例模式
    # 其他所有的程序中的 admin 通过引入,用的都是这个对象 
    site=AdminSite()
    """
     admin.py 中对表进行注册操作
    """
    from django.contrib import admin
    from rbac.models import *
    # Register your models here.
    
    # 基于模块的单例模式从而实现所有的注册表都使用的同一个 admin.site 对象
    admin.site.register(User)
    admin.site.register(Role)
    admin.site.register(Permission)

    URL 分发核心代码

      调用 urls() 方法

      然后继续调用 get_urls() 方法

         遍历所有注册表,进行URL 的拼接合成最后生成一个列表返回给 urls.py

       最终在urls.py 进行调用

    """
    urls.py
    
    urls.py 中全部写成了一条
     所有的结果都在调用 urls方法后拿到
    """
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    ]
    """
    admin 设计url 核心
    
    """
    class AdminSite(object):
        def get_urls(self):
    
            urlpatterns = [
                url(r'^$', wrap(self.index), name='index'),
                url(r'^login/$', self.login, name='login'),
                url(r'^logout/$', wrap(self.logout), name='logout'),
                url(r'^password_change/$', wrap(self.password_change, cacheable=True), name='password_change'),
                url(r'^password_change/done/$', wrap(self.password_change_done, cacheable=True),
                    name='password_change_done'),
                url(r'^jsi18n/$', wrap(self.i18n_javascript, cacheable=True), name='jsi18n'),
                url(r'^r/(?P<content_type_id>d+)/(?P<object_id>.+)/$', wrap(contenttype_views.shortcut),
                    name='view_on_site'),
            ]
            valid_app_labels = []
            
            # 遍历注册过的表,对每个表生成 相应的 url 进行链接起来 
            for model, model_admin in self._registry.items():
                urlpatterns += [
                    url(r'^%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 += [
                    url(regex, wrap(self.app_index), name='app_list'),
                ]
            # 返回给urls 得出的 urls列表
            # 所有的urls 保存在 urlpatterns列表里面
            return urlpatterns
        
        # 调用 get_urls 获得全部的结果
        def urls(self):
            # 给urls.py 返回回去
            return self.get_urls(), 'admin', self.name 

    ps:

      url 的设计和分发合成是什么时候完成?

      答案:

        在项目启动的时候就完成

        在表进行注册后,就已经生成了,而不是url来了再生成

        本质上 django 启动就已经是启动了文件,不然你的admin 单例从何而来

    模拟完成一个 Xadmin 组件实现 admin 组件的功能

    """
    自己实现一个 Xadmin 模块来替换掉 admin
    
      和 admin 一样需要 
          启动
          注册
          url 分发
    """
    
    
    
    """
    启动
    """
    # setting.py 
    INSTALLED_APPS = [
        ...
        'Xadmin.apps.XadminConfig',
        'app01.apps.App01Config',
        'app02.apps.App02Config',
    ]
    
    # apps.py
    from django.apps import AppConfig
    from django.utils.module_loading import autodiscover_modules
    
    # Xadmin.py
    class XadminConfig(AppConfig):
        name = 'Xadmin'
        """
        启动 
        """
        def ready(self):
            autodiscover_modules('Xadmin')
    
    
    class ModelXadmin(object):
        def __init__(self,model,site):
    
            self.model=model
            self.site=site
        
        """    
        url 分发
        二级分发和视图函数放在 配置类里面
        不放在 注册类里面的原因:
            因为注册类 单例生成 导致所有的注册表的self里面无法区分出来彼此的 配置类
            如果放在 配置类中 self 就是注册表自己对应的 配置类 根本拿不到想要的数据(比如 表 本身)
            比如 在 配置类 中 self.model 就是那个表,(在init 中注册的都可以随便拿来用了)
        """     
        def list_view(self, request):
            print("self.model",self.model)
    
            data_list=self.model.objects.all()
            print("data_list",data_list)
            return render(request, 'list_view.html',{"data_list":data_list})
    
        def add_view(self, request):
            return render(request, 'add_view.html')
    
        def change_view(self, request, id):
            return render(request, 'change_view.html')
    
        def delete_view(self, request, id):
            return render(request, 'delete_view.html')
        
        
        def get_urls2(self):
            temp = []
            temp.append(url(r"^$", self.list_view))
            temp.append(url(r"^add/$", self.add_view))
            temp.append(url(r"^(d+)/change/$", self.change_view))
            temp.append(url(r"^(d+)/delete/$", self.delete_view))
            return temp
    
        @property
        def urls2(self):
            return self.get_urls2(), None, None
    
    
    class XadminSite(object):
        def __init__(self,name="admin"):
            self._registry={}
    """
    注册 
    """        
        def register(self, model, admin_class=None, **options):
            if not admin_class:
                admin_class = Modeladmin
            self._registry[model] = admin_class(model, self) 
    
    """
    url 分发
    """    
        def get_urls(self):
            temp = []
            for model, admin_class_obj in self._registry.items():
                app_name = model._meta.app_label
                model_name = model._meta.model_name
                temp.append(url(r'^{0}/{1}/'.format(app_name, model_name), admin_class_obj.urls2), )
            return temp
            
        @property
        def urls(self):
            return self.get_urls(),None,None
            
            
    site=XadminSite()        
    
    # url.py from Xadmin.service.Xadmin import site urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^Xadmin/', site.urls), ] """ 其他的程序使用方式

      和以往admin的方式基本一致
    """ """ 启动 """ # setting.py INSTALLED_APPS = [ ... 'app01.apps.App01Config', "app02.apps.App02Config" ] # apps.py from django.apps import AppConfig class App01Config(AppConfig): name = 'app01' # Xadmin.py from Xadmin.service.Xadmin import site, ModelXadmin """ 注册 """ site.register(Book, BookConfig)
  • 相关阅读:
    ubuntu下在apache部署python站点
    MySQL设置从库只读模式
    mysql数据库,创建只读用户
    BUG处理流程说明
    bug的处理流程
    nginx 502 Bad Gateway 错误解决办法
    Linux下批量替换文件内容方法
    centos 安装pecl
    php学习资源
    Docker容器进入的4种方式(转)
  • 原文地址:https://www.cnblogs.com/shijieli/p/10169743.html
Copyright © 2020-2023  润新知