1月24日学习内容整理:Django的admin组件源码分析及流程

一、单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

》》》基于_ _new_ _方法,在init之前执行的方法

》》》基于模块:其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

在一个Django程序中,模块被加载执行一次后再导入的话就不会再执行模块中的代码了

》》》基于装饰器decorator

》》》使用元类(metaclass)

 

二、admin的源码执行流程

admin源码的核心是两个类:

》》》ModelAdmin:主要用来定制样式,也就是页面效果

》》》AdminSite:主要做admin应用,也就是增删改查的功能

1、Django项目启动时,会按照settings中配置的注册app顺序依次加载app文件,也就会执行app文件中所有的_ _init_ _方法。如下图,第一个就是admin

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

admin中的_ _init_ _文件中的autodiscover_modules('admin', register_to=site)方法就会按顺序扫描加载每一个注册的app中的admin.py文件并执行

2、执行app的admin文件:

#admin.py

class BookAdmin(admin.ModelAdmin):
    list_display = ("title",'publishDate', 'price')

admin.site.register(Book, BookAdmin) 
admin.site.register(Publish)

查看admin源码,admin.site就是一个单例对象,对于AdminSite类的一个单例模式,执行的每一个app中的每一个admin.site都是一个对象,自始至终只有这一个对象

接下来就会执行这个对象的register方法,查看源码,核心就是以下内容,首先判断是否有自定义的样式类,再是创建一个字典,添加一组键值对,键就是传入的model的类对象,也就是models.py中定义的类,对应的值是自定义样式类的对象或者是ModelAdmin对象

class ModelAdmin(BaseModelAdmin):pass

def register(self, model_or_iterable, admin_class=None, **options):
    if not admin_class:
            admin_class = ModelAdmin
    # Instantiate the admin class to save in the registry
    self._registry[model] = admin_class(model, self)

每一个app的admin文件执行完后,我们就会得到一个字典,键就是model类,值是样式类(ModelAdmin或自定义的)的对象这样一组组键值对,并且始终只有一个AdminSite对象

3、到这一步admin注册就结束了,接下来就是等待用户的URL

4、admin的URL配置

全局urls文件中

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

urls方法的源码,核心内容如下,主要就是在调用get_urls方法,这个方法就会定义一个空列表,循环我们注册admin完毕时得到的字典,利用app文件名和model的类名拼接再加上视图函数得到一个个的url方法对象,把这一个个对象放到这个空列表中,在返回这个列表,对于全局urls文件来说,就相当于include做了一个一个的URL拼接

实际上,admin.site对象的urls方法就是实现路由分发的,使得一条路由能够代表多条URL

class AdminSite(object):
    
     def get_urls(self):
        from django.conf.urls import url, include
      
        urlpatterns = []

        # Add in each model's views, and create a list of valid URLS for the
        # app_index
        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

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

 

posted @ 2018-01-24 14:35  九二零  阅读(99)  评论(0编辑  收藏  举报