• Django之admin源码浅析


    Django之admin源码解析

    原文链接:https://www.jianshu.com/p/006ec45bcf1a
    

    1. 启动

    1. Django启动时,自动加载settings配置文件中的installed_apps,
       然后加载每个apps对应的admin.py文件:
     
     
    django/admin/contrib/__init__.py 文件下的	
    ......
    def autodiscover():
    	autodiscover_modules('admin', register_to=site)
    ......
    

    2. 执行admin.py文件:

    from django.contrib import admin
    from blog import models
    
    # 自定义前端admin显示的字段
    class UserInfo(admin.ModelAdmin):
    	list_display = ("username", "phone", "email", 'blog')
    
    admin.site.register(models.UserInfo, UserInfo)
    
    class ArticleAction(admin.ModelAdmin):
    	list_display = ['title', 'user']
    
    # 注册要显示的表名:site 为注册类的实例---site = AdminSite()
    admin.site.register(models.Article, ArticleAction)
    admin.site.register(models.Article2Tag)
    admin.site.register(models.ArticleDetail)
    admin.site.register(models.ArticleUpDown)
    admin.site.register(models.Blog)
    admin.site.register(models.Category)
    admin.site.register(models.Comment)
    admin.site.register(models.Tag)
    

    3. admin.site 对象解析

    这段源码的逻辑是判断register中是否传入了admin_class参数,如果没有传,就是用默认的参数ModelAdmin。
    延伸出来上面在自定义admin_class时为什么必须继承admin.ModelAdmin?
    
    这是因为admin.ModelAdmin中的参数有很多,我们在自定义时不可能将所有参数都修改,或者重写,那样就太麻烦了。
    主动继承admin.ModelAdmin,我们只需要修改我们想要设置的参数,其他的就可以使用原来的参数了。
    
    
    
    django/admin/contrib/sites.py 文件下的
    
    
    class AdminSite(object):
    
    	def __init__(self, name='admin'):
    	
    		# model_class class -> admin_class instance
    		self._registry = {}  
    		
    	# admin.site.register方法
    	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
    		# register这个方法的最后这段源码是将admin_class类传入model来实例化对象完成注册!!!
    		self._registry[model] = admin_class(model, self)
    	......
    	
    # 单例模式,程序只允许存在一个实例
    site = AdminSite()
    

    4. Django中的路由分发的两种设置方式

    第一种:include('py文件')
    
    	from django.conf.urls import url, include
    	
    	urlpatterns = [
    		url(r'^admin/', admin.site.urls),
    		url(r'^index/', include(app01)),
    	]
    	
    	
    第二种:第二种:url('正则表达式',([ url列表 ],None,None)) 规则。
    
    	其中第一个None代表 app名,第二个代表模型类名,但是我们基本用不到,所以就先不关注它们。
    	
    	url(r"blogcenter/", ([
                   url(r"article/", ([
                                      url(r"del_article/", del_article),
                                      url(r"edit_article/", edit_article),
                                      url(r"add_article/", add_article),
                                  ], None, None)),
    
                   url(r"backend/", views.backend),
               ], None, None))
    

    5. admin中路由的设计方式

    url(r'^admin/', admin.site.urls),
    
    # site.urls: site对象的静态方法
    django/admin/contrib/sites.py 文件下的
    
    
    class AdminSite(object):
    
    
    	def get_urls(self):
    		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
    

    6. 默认配置类中的get_urls 与 urls

    class ModelAdmin(BaseModelAdmin):
    	"Encapsulates all admin options and functionality for a given model."
    
    	list_display = ('__str__',)
    	list_display_links = ()
    	list_filter = ()
    	list_select_related = False
    	list_per_page = 100
    	list_max_show_all = 200
    	list_editable = ()
    	......
    
    	def __init__(self, model, admin_site):
    		self.model = model
    		self.opts = model._meta
    		self.admin_site = admin_site
    		super(ModelAdmin, self).__init__()
    
    	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()
    

    7. admin 源码总结

    - 通过以上简略源码可以了解到几点:
    
    - self._registry 是以model模型表为键,对应的model配置类对象为值
    
    - for model, model_admin inself._registry.items():
    	这句源码中,model是个模型表名,model_admin是对应的model配置类实例对象
    
    - model._meta.model_name :模型表的名称
    
    - model._meta.app_label :模型表所在app的名称
    
    - model_admin.urls:model_admin所代表的是对应model的配置类,通过调用配置类的urls方法,
    得到相应的URL和视图函数的对应关系,进而返回前端所需的渲染数据。
    
    - 列表urlpatterns中最后得到是注册model表对应的所有urls,其实就是按照这种规则的路由分发来设计的--->url('正则表达式',([ url列表 ],None,None))
    希望你眼眸有星辰,心中有山海,从此以梦为马,不负韶华
  • 相关阅读:
    二进制文件
    Python的特殊成员
    中标麒麟Linux7 如何关闭广播消息
    双重循环输出
    输出星期数
    九九乘法表
    打印菱形
    加法表
    求100以内所有偶数和
    猜大小
  • 原文地址:https://www.cnblogs.com/daviddd/p/12126391.html
Copyright © 2020-2023  润新知