django—admin的执行流程

1. Django启动时

自动加载settings配置文件中的installed_apps,然后执行如下源码函数按照顺序依次加载apps对应的admin.py文件:

#此方法在admin 的__init__.py中
def
autodiscover(): autodiscover_modules('admin', register_to=site)

2、执行admin.py文件下的代码

from django.contrib import admin
from app01 import models
# Register your models here.
class BookConfig(admin.ModelAdmin):            # 下面数组配置 进入admin可视化才能看到
    list_display = ['title','price','publish']    # 多字段展示
    list_display_links = ['title','price']        
    search_fields = ['title','price']             #指定查询字段
    list_filter = ['publish','authors']           #展示关联外键用这个  其他字段的无效

    def patch_init(self,request,queryset):
        queryset.update(price=666)
    patch_init.short_description = '价格批量处理'
    actions = [patch_init]


admin.site.register(models.Book,BookConfig)
admin.site.register(models.Author)
admin.site.register(models.Publish)
admin.site.register(models.AuthorDetail)

3. 执行Django中admin包下的init中的AdminSite(object)类

class AdminSite(object):
       .........
site = AdminSite()

注意:这里应用的是一个单例模式(通过python模块导入的方式实现的),对于AdminSite类的一个单例模式,执行的每一个app中的每一个admin.site都是一个对象

 

4. 通过AdminSite类的对象执行AdminSite类中的register方法

admin.site.register(models.Book,BookConfig)
admin.site.register(models.Author)
admin.site.register(models.Publish)
admin.site.register(models.AuthorDetail)
def register(self, model_or_iterable, admin_class=None, **options):
        """
        Registers the given model(s) with the given admin class.
        """
        if not admin_class:
            admin_class = ModelAdmin

# 这段源码的逻辑是判断register中是否传入了admin_class参数,如果没有传,就是用默认的参数ModelAdmin。
延伸出来上面在自定义admin_class时
为什么必须继承admin.ModelAdmin?
# 进入admin.ModelAdmin中 可以发现其中有很多参数
我们在自定义时不可能将所有参数都修改,或者重写,那样就太麻烦了。主动继承admin.ModelAdmin,我们只需要修改我们想要设置的参数,其他的就可以使用原来的参数了。
if not model._meta.swapped:
    # If we got **options then dynamically construct a subclass of
    # admin_class with those **options.
      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)
           #将每个admin_class传入对应model实例化从而注册,以model模型类 为键,
           #对应的model配置类对象为值得形式添加到self._registry中。
# Instantiate the admin class to save in the registry self._registry[model] = admin_class(model, self)

register这个方法的最后这段源码是将admin_class类传入model来实例化对象完成注册!!!

 

5.amdin中url的设计

首先应该知道Django中的路由分发的设置方式现在了解两种:
  • 第一种:include('py文件')
from django.conf.urls import url, include

url(r'^blogcenter/', include(blogcenter_urls)),

而 blogcenter_urls.py↓ 中

from django.conf.urls import url
from blog import views

urlpatterns = [
    url(r'^backend/$',views.Backend.as_view()),
]
  • 第二种:url('正则表达式',([ url列表 ],None,None)) 规则。其中第一个None代表 app名,第二个代表模型类名,但是我们基本用不到,所以就先不关注它们。
url(r"blogcenter/", 
  ([     url(r
"del_article/", del_article),     url(r"edit_article/", edit_article),     url(r"add_article/", add_article),   ], None, None)),

接下来看一下Django初始配置的url:

#一开始就有的
url(r'^admin/', admin.site.urls),

通过源码可以看出urls是site对象可以调用的静态方法,而site对象是由AdminSite类实例化出来的,从而就可以找到urls的归属地了。
一下为源码:

 @property
 def urls(self):
    return self.get_urls(), 'admin', self.name

可以看出urls是AdminSite类的静态方法,它的返回值是一个元组,再看self.get_urls()是什么?

def __init__(self, name='admin'):
        self._registry = {}  # model_class class -> admin_class instance
      .......

def register(self, model_or_iterable, admin_class=None, **options):
     """
     Registers the given model(s) with the given admin class.
     """
     if not admin_class:
         admin_class = ModelAdmin
         ........

      #将每个admin_class传入对应model实例化从而注册,以model模型类 为键,
      #对应的model配置类对象为值得形式添加到self._registry中。
      self._registry[model] = admin_class(model, self)   

def get_urls(self):
    # Add in each model's views, and create a list of valid URLS for the
    # app_index
    valid_app_labels = []
    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

 

配置类中的get_url(),和urls方法  也就是    admin.site.register(models.Book,BookConfig) 中 BookConfig中的方法:

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()

通过以上简略源码可以了解到几点:

  • self._registry 是以model模型表为键,对应的model配置类对象为值
  • for model, model_admin in self._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))

 

posted @ 2019-03-25 22:58  萤huo虫  阅读(364)  评论(0)    收藏  举报