一、单例模式
单例模式(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.pyclass 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):passdef 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