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))
相關文章
相關標籤/搜索