为了可以在django应用中使用admin管理界面,可以在urls.py中增加以下一些代码:
# Uncomment the next two lines to enable the admin: from django.contrib import admin admin.autodiscover() ... urlpatterns = patterns('', ... # Uncomment the next line to enable the admin: (r'^admin/', include(admin.site.urls)), ... )
下面来分析一下admin对应的urls是如何引用的。
首先来看autodiscover()
源码位于django\contrib\admin\__init__.py中:
def autodiscover(): ... for app in settings.INSTALLED_APPS: mod = import_module(app) # Attempt to import the app's admin module. try: before_import_registry = copy.copy(site._registry) import_module('%s.admin' % app) except: site._registry = before_import_registry
这个函数将settings.INSTALLED_APPS列表中的app进行注册或导入相关模块,如admin有关的进行注册,以后可以使用site._registry来进行引用。(此处不包含model的注册)
真正产生urls的是(r'^admin/', include(admin.site.urls))。
admin.site是在django\contrib\sites.py中的最后一行生成的。
site = AdminSite()
所以admin.site.urls实际上是类AdminSite的属性。
def urls(self): return self.get_urls(), self.app_name, self.name urls = property(urls)
从上面的代码看生成的关键在于类AdminSite的方法get_urls()中
def get_urls(self): ... # Admin-site-wide views.(Admin-site范围的视图) urlpatterns = patterns('', url(r'^$', wrap(self.index), name='index'), 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>.+)/$', 'django.views.defaults.shortcut'), url(r'^(?P<app_label>\w+)/$', wrap(self.app_index), name='app_list') ) # Add in each model's views.(增加每个model的视图) for model, model_admin in self._registry.iteritems(): urlpatterns += patterns('', url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name), include(model_admin.urls)) ) return urlpatterns
对于每个model的url是通过include(model_admin.urls)来进行加入的.而每个model是使用admin.site.register(model_name,modelAdmin)等形式来注册的.下面来查看AdminSite的register函数:
def register(self, model_or_iterable, admin_class=None, **options): ... for model in model_or_iterable: ... if options: # For reasons I don't quite understand, without a __module__ # the created class appears to "live" in the wrong place, # which causes issues later on. options['__module__'] = __name__ admin_class = type("%sAdmin" % model.__name__, (admin_class,), options) ... # Instantiate the admin class to save in the registry self._registry[model] = admin_class(model, self)
可以看出get_urls()中model_admin应该是类ModelAdmin的实例.所有model_admin.urls实际上是类ModelAdmin的属性,具体的与admin-site视图的urls处理类似了.
def get_urls(self): ... urlpatterns = patterns('', 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'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns def urls(self): return self.get_urls() urls = property(urls)