Django——admin源码分析
在Django中,如果我们新建一个项目,只要在admin.py文件中注册,就可以对其相应的文件进行增删改查操作。
而我们在路由系统中只看到了一条信息:url(r'^admin/', admin.site.urls),但是我们确实是可以进行增删改查操作?这其中到底有什么端倪了?
下面我们会从Django源码的角度来分析admin执行流程。
1.循环加载执行所有已经注册的app中的admin.py文件
def autodiscover(): autodiscover_modules('admin', register_to=site)
2.执行admin.py文件中的代码
class BookAdmin(admin.ModelAdmin): list_display = ("title",'publishDate', 'price') admin.site.register(Book, BookAdmin) admin.site.register(Publish)
3.admin.site
这里应用的是一个单例模式,对于AdminSite类的一个单例模式,执行的每一个app中的每一个admin.site都是一个对象。
4.执行register方法
admin.site.register(Book, BookAdmin)
admin.site.register(Publish)
register函数源码信息:
class AdminSite(object): ...... def register(self, model_or_iterable, admin_class=None, **options): if not admin_class: #如果没有设置admin_class这个类 admin_class = ModelAdmin #那么就会执行默认的样式 if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] for model in model_or_iterable: #在名称列表中循环 ......(省略) self._registry[model] = admin_class(model, self) #这句话是关键
执行完admin.site.register()代码之后,就创建_registry这个字典,表名为键,admin_class(样式)为值,我们也可以打印这个字典。
到这里,注册结束。
5.admin的URL配置
上面已经注册成功了,现在该解释URL自动生成的过程了。
我们先来分析Django源码是如何实现的,从url(r'^admin/', admin.site.urls)出发,我们可以直接找urls函数
@property def urls(self): return self.get_urls(), 'admin', self.name
随后我们去找get_urls()这个函数,
def get_urls(self): from django.conf.urls import url, include 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) # Admin-site-wide views. urlpatterns = [ url(r'^$', wrap(self.index), name='index'), url(r'^login/$', self.login, name='login'), url(r'^logout/$', wrap(self.logout), name='logout'), url(r'^password_change/$', wrap(self.password_change, cacheable=True), name='password_change'), url(r'^password_change/done/$', wrap(self.password_change_done, cacheable=True), name='password_change_done'), url(r'^jsi18n/$', wrap(self.i18n_javascript, cacheable=True), name='jsi18n'), url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$', wrap(contenttype_views.shortcut), name='view_on_site'), ]
关于urlpatterns是如何生成的我们不了解,只知道在这里就生成了增删改查的URL,现在我们用自己的手段来实现这一过程。
6.自定义实现admin配置
首先,需要用到路由分发,就像下面这样:
def test01(request): return HttpResponse("test01") def test02(request): return HttpResponse("test02") def test03(request): return HttpResponse("test03") urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^kebi/',([ url(r'^test01/', test01), url(r'^test02/', test02), #一条URL包含很多条内置的URL,这个部分可以封装到函数中 url(r'^test03/', test03), ],None,None)) ]
里面还可以再次封装,就像这样:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def test01(request): return HttpResponse("test01") def test0203(request): return HttpResponse("test0203") def test0204(request): return HttpResponse("test0204") def test05(request): return HttpResponse("test05") urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^kebi/',([ url(r'^test01/', test01), url(r'^test02/', ([ url(r'^test03/', test0203), url(r'^test04/', test0204), ],None,None)), url(r'^test05/', test05), ],None,None)) ]
我们将其封装到一个函数之中:
from django.conf.urls import url from django.contrib import admin from django.shortcuts import HttpResponse def test01(request): return HttpResponse("test01") def get_urls(): urlpatterns = [] for model,model_config in admin.site._registry.items(): model_name = model._meta.model_name #model可以说是类名,现在要获取字符串拼接,获取类名,属于字符串 app_label = model._meta.app_label #app名,属于字符串 urlpatterns.append(url('%s/%s'%(app_label,model_name),test01)) return urlpatterns urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^kebi/',(get_urls(),None,None)) #只要urlpatterns有值,就可以做分发 ]
这样就生成了:
http://127.0.0.1:8000/kebi/app02/publish
http://127.0.0.1:8000/kebi/app01/authors
仅仅如此,还没有满足要求,那么就在做一次分发,就像这样:
from django.contrib import admin from django.shortcuts import HttpResponse def show_list(request): return HttpResponse("查看列表") def add_list(request): return HttpResponse("增加列表") def change_list(request,id): return HttpResponse("更改列表") def delete_list(request,id): return HttpResponse("删除列表") def get_urls_func(): temp = [] #现在来写增删改查 temp.append(url('^$',show_list)) temp.append(url('/add/$',add_list)) temp.append(url('/(\d+)/change/$',change_list)) temp.append(url('/(\d+)/delete/$',delete_list)) return temp def get_urls(): urlpatterns = [] for model,model_config in admin.site._registry.items(): model_name = model._meta.model_name #model可以说是类名,现在要获取字符串拼接 app_label = model._meta.app_label #app名 urlpatterns.append(url('%s/%s'%(app_label,model_name),(get_urls_func(),None,None))) return urlpatterns urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^kebi/',(get_urls(),None,None)) #只要urlpatterns有值,就可以做分发 ]
现在能够访问的有这些:
#两个表都会自动生成增删改查的URL http://127.0.0.1:8000/kebi/app02/publish http://127.0.0.1:8000/kebi/app02/publish/add http://127.0.0.1:8000/kebi/app02/publish/1/change http://127.0.0.1:8000/kebi/app02/publish/2/delete http://127.0.0.1:8000/kebi/app01/authors http://127.0.0.1:8000/kebi/app01/authors/add http://127.0.0.1:8000/kebi/app01/authors/1/change http://127.0.0.1:8000/kebi/app01/authors/2/delete
下面是效果: