Django Admin源碼流程

1、總體看Admin執行流程 1. 啓動adminjavascript

首先須要將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.registerjava

django啓動的時候,順序爲:先register,而後urls分配    
 先看看admin.siter.register作了什麼

[Python] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40django

首先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 採用的是模板的單例模式app

在AdminSite中定義了一個字典
      字典的key是模型類,value是ModelAdmin

3、admin.site.urlside

[Python] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40函數

使用裝飾器,將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中註冊模型類的時候:

[Python] 純文本查看 複製代碼
?
1
admin.site.register(models.UserInfo) # 註冊的時候沒有傳入admin_class,默認使用的是ModelAdmin ui

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

[Python] 純文本查看 複製代碼
?
1
2
3
4
for model, model_admin in self._registry.items():url

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

[size=1.375em]設計

4、ModelAdmin.urls
[Python] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def get_urls(self):code

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

[size=1.5em]

[size=1.5em]5、最終的url

[Python] 純文本查看 複製代碼?1url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)),

相關文章
相關標籤/搜索