Django的admin.py注冊流程


通常創建一個Django項目的時候,在Django的配置文件settings.py中,都會有下面的這段配置:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
]

這段配置文件是Django用來注冊所創建的應用的.

例如這里在創建Django項目時,添加了一個名為"app01"的應用.

在所創建的項目中,存在着一個名為"apps.py"的文件,這個文件的內容如下:

    from django.apps import AppConfig
    
    class App01Config(AppConfig):
        name = 'app01'

在這個文件中,以所注冊的應用名加"Config"定義的類中,其實還有一個方法:

    from django.apps import AppConfig
    
    class App01Config(AppConfig):
        name = 'app01'
        
        def ready(self):
            pass

這個ready是程序在執行路由映射之前執行這個方法.那這個函數有什么用呢??

admin.py文件中,可以注冊數據庫中數據表,這樣方便在Django的后台管理所注冊的數據庫.

admin.site.register(models.UserInfo)

把models.py中的類注冊在這里后,就會生成在后台進行管理這個數據表的四個URL.

/admin/app01/userinfo/
/admin/app01/userinfo/add/
/admin/app01/userinfo/1/change/
/admin/app01/userinfo/2/delete/

實際上,把想在Django后台管理的數據表寫在admin.py文件中以后,Django會執行一個autodiscover_modules方法.

def autodiscover():
    autodiscover_modules('admin', register_to=site)

Django執行autodiscover_modules后,admin.py文件也就會執行了.

只有admin.py文件執行過后,Django的路由中生成在Django的后台中對已注冊的數據表進行增刪查改的路由關系映射.

admin執行后,又會執行site函數.

site又會執行什么樣的操作呢??進入site函數,在sites.py文件的最后一行,可以看到:

site = AdminSite()

site是AdminSite這個類的一個單例模式.這樣一來,執行site方法就相當於執行了AdminSite這個類中的__init__方法.

def __init__(self, name='admin'):
    self._registry = {}
    self.name = name
    self._actions = {'delete_selected': actions.delete_selected}
    self._global_actions = self._actions.copy()
    all_sites.add(self)

執行admin.site方法就相當於實例化一個AdminSite對象,然后這個對象會調用AdminSite這個類中的register方法.

    def register(self, model_or_iterable, admin_class=None, **options):
    
        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:
         
                    options['__module__'] = __name__
                    admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
    
                self._registry[model] = admin_class(model, self)

register方法的前兩個參數都是一個類名.

可以看到register方法的最后會把其參數定義的類加入到__init__方法中_registry方法定義的那個空字典中.

同時對參數中的類進行實例化.

類進行實例化的參數為這個類本身以及site本身.類似下面的情形,

    {
        models.UserInfo: UserInfoAdmin(models.UserInfo,site對象),
        models.UserGroup: ModelAdmin(models.UserGroup,site對象),
    }

同時,由於對AdminSite進行實例化的時候使用了單例模式,所以程序第一次執行完后,系統中會一直存在這個site對象.

這樣一來,admin.py程序后,就相當於是把在admin.py中注冊的類以及對應的配置文件實例化之后的對象全部封裝到AdminSiteregister方法中了.

admin.py執行完成后,Django才開始執行urls.py中配置的路由關系映射.

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', index),
]

如上所示,在路由關系映射中,Django也會再執行一次admin.site.urls的方法.

進入urls方法中,可以看到

@property
def urls(self):
    return self.get_urls(), 'admin', self.name

urls方法是執行了一個get_urls方法.再次進入get_urls方法

    def get_urls(self):
        from django.conf.urls import url, include
        
        ...
    
        valid_app_labels = []
        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)
        ...
        
        return urlpatterns

get_urls方法中,循環_registry這個字典,為字典中的每個類生成Django后台使用的增刪查改等操作的url.

urlpatterns += [
    url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)),
]

在這里,

* model._meta.app_label     表示的是Django中添加的應用名
* model._meta.model_name    表示Django的數據庫中的表名

把這兩個字符串以"/"進行拼接后生成新的字符串

urlpatterns與這個字符串進行拼接,生成了新的urlpatterns.

在這一行的后邊,model_admin又會調用這個對象中的url函數間接執行get_url方法來生成路由關系映射的后半部分.

這個生成的后半部分路由再與前面的新urlpatterns進行拼接,依次循環就生成在Django后台進行數據表操作的路由關系映射.

綜上所述,在admin.py中注冊models.py中的類的流程

1. 先執行admin.py,使用單例模式創建一個admin.site的對象
2. 在admin.site對象中,把admin.py中定義的類全部注冊,並把類中所有的配置全部傳遞到admin.site對象的_registry生成的字典中
3. 在生成url時,url會循環site中的類,為每一個類生成相應的url

這就是在admin.py中注冊數據表后Django的執行流程.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM