django----admin源码流程
Admin源码分析
1、启动 python manage.py runserver 时候,会自动执行每一个 app 下的 admin.py

2、注册模型(执行每一个app下的admin.py 文件)

3、设计url
将AdminSite实例挂载到指定的URLconfig中
admin.site.urls 目的是动态生成 一系列 url 将他们添加到 urlpatterns 中(后面有分析)

对 AdminSite 类分析
每一个模型都可以指定一个ModelAdmin ,封装了该模型的特定的管理功能
本质上实例化的是AdminSite()

一部分AdmainSite 源码
class AdminSite:
def __init__(self, name='admin'):
self._registry = {} # AdminSite 初始化一个空字典
self.name = name
self._actions = {'delete_selected': actions.delete_selected}
self._global_actions = self._actions.copy()
all_sites.add(self)
def register(self, model_or_iterable, admin_class=None, **options): #用来注册
admin_class = admin_class or 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 指的是UserAdmin,看是否用户自定制了admin, admin.site.register(models.UserInfo, UserAdmin)
options['__module__'] = __name__
admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
self._registry[model] = admin_class(model, self)
admin.site.urls 中的 urls 属性
admin.site.urls 返回的是一个元祖 元祖的第一个参数是一个列表 由 get_urls() 返回
get_urls() 的目的为了将app_name 和 model_name 动态添加到 urlpatterns = [] 里面 (包括所有的url,例如 <URLPattern 'logout/' [name='logout']>等 login)

class AdminSite:
@property
def urls(self):
return self.get_urls(), 'admin', self.name
def get_urls(self):
from django.urls import include, path, re_path
from django.contrib.contenttypes import views as contenttype_views
def wrap(view, cacheable=False):
def wrapper(*args, **kwargs):
return self.admin_view(view, cacheable)(*args, **kwargs)
wrapper.admin_site = self
return update_wrapper(wrapper, view)
urlpatterns = [
path('', wrap(self.index), name='index'),
path('login/', self.login, name='login'),
path('logout/', wrap(self.logout), name='logout'),
path('password_change/', wrap(self.password_change, cacheable=True), name='password_change'),
path(
'password_change/done/',
wrap(self.password_change_done, cacheable=True),
name='password_change_done',
),
path('jsi18n/', wrap(self.i18n_javascript, cacheable=True), name='jsi18n'),
path(
'r/<int:content_type_id>/<path:object_id>/',
wrap(contenttype_views.shortcut),
name='view_on_site',
),
]
valid_app_labels = []
for model, model_admin in self._registry.items():
urlpatterns += [
path('%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)
if valid_app_labels:
regex = r'^(?P<app_label>' + '|'.join(valid_app_labels) + ')/$'
urlpatterns += [
re_path(regex, wrap(self.app_index), name='app_list'),
]
return urlpatterns
超级简单模拟 admin.site.urls


高级操作。类似Django中的admin.site.urls
admin.site.urls的本质:它读取_registry所有字典里面的数据,为字典里面的每一个类生成了4个url
from django.shortcuts import render,HttpResponse
from django.contrib import admin
from django.urls import path,re_path
def login(request):
return HttpResponse("ok")
def change_list(request):
return HttpResponse("列表页面")
def add_view(request):
return HttpResponse("添加页面")
def change_view(request,nid):
return HttpResponse("修改页面")
def delete_view(request,nid):
return HttpResponse("删除页面")
def test(req):
return HttpResponse('test')
def index(request):
return HttpResponse("index")
class AdminSite:
def __init__(self, name='admin'):
self.name = name
@property
def urls(self):
print("zhxign")
urlpatterns = [
path('',index), #相当于 admin "http://127.0.0.1:8000/admin/"
path('login',login)
]
for model_class, v in admin.site._registry.items():
print(model_class) # 打印的是每一个类<class 'app01.models.UserInfo'>
cls_name = model_class._meta.model_name # 当前类名称的小写
app_name = model_class._meta.app_label # 当前app的名称
urls_list = re_path(r'^{0}/{1}/$'.format(app_name, cls_name), change_list, name="login")
urlpatterns.append(urls_list) #查
add_url = re_path(r'^{0}/{1}/add/$'.format(app_name, cls_name), add_view, name="login") #增
urlpatterns.append(add_url)
change_url = re_path(r'^{0}/{1}/(\d+)/change/$'.format(app_name, cls_name), change_view, name="login") #改
urlpatterns.append(change_url)
del_url = re_path(r'^{0}/{1}/(\d+)/del/$'.format(app_name, cls_name), delete_view, name="login") #删
urlpatterns.append(del_url)
return urlpatterns,"admin",self.name
site = AdminSite()

补充:利用include 做分发url 功能
include函数的返回值 return (urlconf_module, app_name, namespace) 为一个数组

如果不使用 include
urlpatterns = [
re_path(r'admin/', admin.site.urls),
path('index/',([
path('', views.index),
path('login', views.login)
],None,None)),
]
include的本质就是:返回了一个元组,元组的第一个是这个模块
include里面
既可以写一个列表include([]),利用include做分发
也可以返回一个字符串:帮我们去找到这个模块,找到所有的映射关系
总结
- admin源码流程
a. 运行程序,找到每一个app中的 admin.py 文件,并加载
- app01.admin.py
- 创建admin.site中的对象
- 执行对象的 register方法,目的:将注册类添加到 _registry中
_registry = {
key是传进来的model value:是ModelAdmin的对象,传了两个参数
models.Role: ModelAdmin(models.Role,admin.site),
models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
models.UserType: ModelAdmin(models.UserType,admin.site)
}
- app02.admin.py
- 用app01.admin中创建那个admin.site对象
- 执行对象的 register方法,目的:讲注册类添加到 _registry中
_registry = {
models.Role: ModelAdmin(models.Role,admin.site),
models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
models.UserType: ModelAdmin(models.UserType,admin.site)
models.Article: ModelAdmin(models.Article,admin.site)
}
admin.site是一个对象(单例模式创建),其中封装了:
_registry = {
models.Role: ModelAdmin(models.Role,admin.site),
models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
models.UserType: ModelAdmin(models.UserType,admin.site)
models.Article: ModelAdmin(models.Article,admin.site)
}
b. urls.py
再次调用 admin.site 对象的 urls属性:
urlpatterns = [
url(r'^admin/', admin.site.urls),
]
class ModelAdmin(object):
def __init__(self,model_class,site):
self.model_class = model_class
self.site = site
def changelist_view(self,request):
data_list = self.model_class.objects.all() #是动态的
return HttpResponse('列表页面')
def add_view(self,request):
return HttpResponse('添加页面')
def delete_view(self,request,nid):
return HttpResponse('删除页面')
def change_view(self,request,nid):
return HttpResponse('修改页面')
def get_urls(self):
urlpatterns = [
url(r'^$', self.changelist_view),
url(r'^add/$', self.add_view),
url(r'^(.+)/delete/$', self.delete_view),
url(r'^(.+)/change/$', self.change_view),
]
return urlpatterns
@property
def urls(self):
return self.get_urls()
class AdminSite(object):
def __init__(self):
self._registry = {}
def register(self,model_class,model_admin):
self._registry[model_class] = model_admin(model_class,self)
def get_urls(self):
"""
models.Role: ModelAdmin(models.Role,admin.site),
models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
models.UserType: ModelAdmin(models.UserType,admin.site)
models.Article: ModelAdmin(models.Article,admin.site)
"""
url_list = []
for model_class,model_admin in self._registry.items(): #利用利用之前已经注册的_registry,动态生成一系列 url,添加到路由中
model_class是一个类
app_name = model_class._meta.app_label
model_name = model_class._meta.model_name
url_list += [
url('%s/%s' %(app_name,model_name,), include(model_admin.urls))
]
return url_list
@property
def urls(self):
return (self.get_urls(), None,None )

浙公网安备 33010602011771号