django admin源碼分析

Django Admin源碼流程

1、總體看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)

 

2、admin.site.register

django啓動的時候,順序爲:先register,而後urls分配javascript

先看看admin.siter.register作了什麼html

 

#首先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)

 

總結:java

 就是實例化了一個AdminSite類,admin.site 採用的是模板的單例模式django

   在AdminSite中定義了一個字典app

   字典的key是模型類,value是ModelAdminide

 3、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匹配規則和對應的視圖函數。ui

當用戶在admin中註冊模型類的時候:url

admin.site.register(models.UserInfo) # 註冊的時候沒有傳入admin_class,默認使用的是ModelAdmin 

會根據下面的代碼添加到urlpatterns中spa

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

 4、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和映射了。

5、最終的url

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

/app01/userinfo/delete

相關文章
相關標籤/搜索