• Django Admin源码流程


    一、整体看Admin执行流程

    1. 启动admin
        首先需要将django.contrib.admin添加到INSTALL_APP中
        当加载django中app的时候,执行每一个app下的admin.py
    2. 注册模型
        每个模型都可以指定一个ModelAdmin
        封装了该模型特定的管理功能
        实例化一个AdminSite,并告诉它模型类和ModelAmin
        admin.site --> 实例化一个AdminSite
        admin.site.register(Book) 注册Book表
    3.  设计URL并将AdminSite实例挂钩到您的URLconfig中
        url(r'admin/',admin.site.urls)

    二、admin.site.register

    django启动的时候,顺序为:先register,然后urls分配

    先看看admin.siter.register做了什么

    #首先admin.site = AdminSite()
    
        class AdminSite(object):
            ....
    
            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):
                # 判断是否自定义了ModelAdmin
                if not admin_class:
                    admin_class = 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:
                            # For reasons I don't quite understand, without a __module__
                            # the created class appears to "live" in the wrong place,
                            # which causes issues later on.
                            options['__module__'] = __name__
                            admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
    
                        # 以传入的model类作为字典的key,ModelAdmin作为字典value
                        self._registry[model] = admin_class(model, self)

    总结:

     就是实例化了一个AdminSite类,admin.site 采用的是模板的单例模式

       在AdminSite中定义了一个字典

       字典的key是模型类,value是ModelAdmin

     三、admin.site.urls

     #使用装饰器,将urls()装饰为属性,urls返回的是一个元组,元组的第一个参数是一个列表,由get_urls()返回
        @property
        def urls(self):
            return self.get_urls(), 'admin', self.name
    
    
        def get_urls(self):
            from django.conf.urls import url, include
            from django.contrib.contenttypes import views as contenttype_views
    
            def wrap(view, cacheable=False):
                .....
                return update_wrapper(wrapper, view)
    
            # Admin-site-wide views.
            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 = []
            #   模型类,ModelAdmin     self._registry字典
            for model, model_admin in self._registry.items():
                urlpatterns += [
                    # url(r'^%s/%s/' % (模型所在的app名, 模型名), include(每个模型对应的ModelAdmin中urls)),
                    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)
                .....
    
            #返回了n个URL
            return urlpatterns

    首先urls是一个函数,被装饰为属性,urls返回一个元组,元组的第一个参数是列表,由get_urls()返回。

    在get_urls()中定义了一个urlpatterns,并最终返回,urlpatterns里面存放的是url匹配规则和对应的视图函数。

    当用户在admin中注册模型类的时候:

    admin.site.register(models.UserInfo) # 注册的时候没有传入admin_class,默认使用的是ModelAdmin 

    会根据下面的代码添加到urlpatterns中

    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)),
        ]

     model._meta.app_label: 是model类存在的app名,就是UserInfo存在哪个app中

    model._mate.model_name:是模型类的类名,小写。这里是userinfo。

    这样就生成了/app01/userinfo/ 这样的url前缀。

    include(model_admin.urls):包含模型类对应ModelAdmin中urls。这里没有指定ModelAdmin,所以使用官方默认的ModelAdmin

     四、ModelAdmin.urls

        def get_urls(self):
            from django.conf.urls import url
    
            def wrap(view):
                def wrapper(*args, **kwargs):
                    return self.admin_site.admin_view(view)(*args, **kwargs)
                wrapper.model_admin = self
                return update_wrapper(wrapper, view)
    
            info = self.model._meta.app_label, self.model._meta.model_name
    
            urlpatterns = [
                url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info),
                url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info),
                url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info),
                url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info),
                url(r'^(.+)/change/$', wrap(self.change_view), name='%s_%s_change' % info),
                # For backwards compatibility (was the change url before 1.9)
                url(r'^(.+)/$', wrap(RedirectView.as_view(
                    pattern_name='%s:%s_%s_change' % ((self.admin_site.name,) + info)
                ))),
            ]
            return urlpatterns
    
        @property
        def urls(self):
            return self.get_urls()

    在ModelAdmin中urls()也是一个函数,被装饰器装饰为属性。get_urls()返回一个urlpatterns.

    红色部分的urlpatterns 表明了django admin为什么注册了一个类之后就为这个类提供了基本的增删改查等基本的url和映射了。

    五、最终的url

    url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)),

    /app01/userinfo/delete

  • 相关阅读:
    我所了解的meta
    移动端遇到的问题
    反编译工具
    Nginx安装及配置免费HTTPS证书
    Python中通过lambda抛异常的奇技淫巧
    理解PEP333-WSGI
    Doker学习笔记之一:安装
    《程序员修炼之道》备忘清单
    日常开发工具列表
    NLP入门资料
  • 原文地址:https://www.cnblogs.com/weihengblog/p/9122509.html
Copyright © 2020-2023  润新知