django--admin源码分析

django有一套强大的admin后台数据库管理工具,通过url(r'^admin/', admin.site.urls)完成对已注册model的增删改成,注册方法是admin.site.register(Book)

基于admin的stark组件

先创建一个app,完成数据库迁移

startapp app01    -->在项目中创建一个应用app01

makemigrations   负责基于你的模型修改创建一个新的迁移
migrate      负责应用迁移,以及取消应用并列出其状态。

在项目的settings.py文件中找到INSTALLED_APPS

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'app02.apps.App02Config',
    'stark.apps.StarkConfig'
]
把创建的应用app注册

找到创建的组件stark下的apps.py文件,在ready()方法里面写上

autodiscover_modules('stark'),作用是可以像admin一样在项目启动时,会在所有的app中扫描加载stark.py.
from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules


class StarkConfig(AppConfig):
    name = 'stark'

    def ready(self):
        '''
        #在INSTALLED_APPS注册过该应用之后,在启动项目时,会找到name=stark的这个app,然后执行ready方法,
        这个方法中主要是做一些初始化任务.
        '''

        autodiscover_modules('stark')   #项目启动时,会把项目中所有app下面的的stark的文件全部加载,和admin一样,都是在启动时扫描所有的admin文件,并加载
写一个类方法ready,作用是项目启动时,做一些初始化任务

分别在app01和app02的models.py中创建model模型

from django.db import models

# Create your models here.

class Book(models.Model):
    title=models.CharField(max_length=32)
    def __str__(self):
        return self.title
app01/models.py
from django.db import models

# Create your models here.


class UserInfo(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32,default=123)
    email=models.EmailField()
    roles=models.ManyToManyField(to="Role")

    def __str__(self):
        return self.name

class Role(models.Model):
    title=models.CharField(max_length=32)
    def __str__(self):
        return self.title
app02/models.py

分别在app01和app02的stark.py文件中进行注册

from stark.service.sites import site
from .models import *
site.register(Book)
app01/stark.py
from stark.service.sites import site
from .models import *

site.register(UserInfo)
site.register(Role)
app02/stark.py

在项目的urls.py中写上自定义组件的路由分发

from django.conf.urls import url
from django.contrib import admin
from stark.service.sites import site

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url('^stark/',site.urls),#模拟admin做的stark组件,
]
项目的urls.py

在stark应用中创建service包,在包下创建site.py来处理url以及url分发

from django.conf.urls import url
from django.shortcuts import HttpResponse,render

class ModelStark(object):
    def __init__(self,model,site):
        self.model=model    #原因是StarkSite类中,self.registry[model]=model_config(model,self)
        self.site=site
    def show_list(self,request):
        ret=self.model.objects.all()
        return render(request,"stark/show_list.html",locals())

    def add_view(self,request):

        return HttpResponse("add_view123.")

    def change_view(self,request,id):
        return HttpResponse("change_view123")

    def del_view(self,request,id):
        return HttpResponse("del_view123")

    def get_urls(self):
        temp=[]
        temp.append(url("^$", self.show_list))
        temp.append(url("^add/$", self.add_view))
        temp.append(url("^(\d+)/change/$", self.change_view))
        temp.append(url("^(\d+)/delete/$", self.del_view))
        return temp

    @property
    def urls(self):
        return self.get_urls()


class StarkSite(object):
    def __init__(self):
        self._registry={}
    def register(self,model,model_config=None):
        if not model_config:
            model_config=ModelStark
        self._registry[model]=model_config(model,self)


    def get_urls(self):
        temp=[]
        # 从已经注册好了的site._registry中取出注册了哪些表名,做url分发
        for model,model_config in self._registry.items():
            model_name = model._meta.model_name
            app_label = model._meta.app_label
            u=url('^%s/%s/'%(app_label,model_name),(model_config.urls,None,None))#做二级url分发
            temp.append(u)
        return temp


    @property
    def urls(self):
        return self.get_urls(),None,None
    
site=StarkSite()    
stark/service/sites.py

知识点:

model类变量下的_meta属性
类名._meta.model_name ==>字符串类型的类名,且全部是小写
类名._meta.app_label ==>app的名字,
print(UserInfo._meta.model_name) #"userinfo"
print(UserInfo._meta.app_label) #"app02" UserInfo是在app02的models.py中定义的类
url方法的分发:
        一级分发:
            url("路径规则",视图)
            url("路径规则1",([
                                url("路径规则2",视图1),
                                url("路径规则3",视图2),
                                url("路径规则4",视图3),
                            ]None,None))
            路径规则1/路径规则2--->视图1
            路径规则1/路径规则3-->视图2
            路径规则1/路径规则4-->视图3
        二级分发:
            url("路径规则",视图)
            url("路径规则1",([
                                url("路径规则2",视图1),
                                url("路径规则3",([
                                                    url("路径规则4",视图2),
                                                    url("路径规则5",视图3),
                                                ],None,None)),
                                url("路径规则6",视图4),
                            ]None,None))
            路径规则1/路径规则2--->视图1
            路径规则1/路径规则3/路径规则4-->视图2
            路径规则1/路径规则3/路径规则5-->视图3
url分发

 

之所以在sites.py中创建两个类,StarkSite是做url分发的,ModelStark是样式类.原因是admin中源码中也是这么定义的,下面就进入到admin的源码分析

-----------------------------------------------------------------------------------------------------------

源码分析

如果要使用django封装好了的admin,就需要在app中创建好model模型之后需要到app的admin.py中进行注册

一.注册

from django.contrib import admin

# Register your models here.
from .models import *


admin.site.register(UserInfo)

class RoleConfig(admin.ModelAdmin):
    change_list_template="change_list.html"
    list_display = ["id","title"]
admin.site.register(Role,RoleConfig)
admin.py示例

1.当django项目启动时,admin应用首先扫描(加载)每一个app下面的admin.py
from django.utils.module_loading import autodiscover_modules

def autodiscover():
    autodiscover_modules('admin', register_to=site)
#autodiscover_modules是项目启动时就扫描所有的app下的admin.py
from django.contrib import admin,按Ctrl点击admin进去就可以看到autodiscover

 

 2.(1)admin.py文件中   

from django.contrib import admin --->点进去admin,from django.contrib.admin.sites import AdminSite,site

加载admin-->sites--->site=AdminSite() (单例模式,无论在什么地方引入,使用的都是同一个对象site)
(2)admin.py
#进行注册
admin.site.register(Book)

 

源码:
class
AdminSite(object): def __init__(self, name='admin'): self._registry = {} self.name = name def register(self, model_or_iterable, admin_class=None, **options):  #指的是类名字,admin_class指的是样式类 if not admin_class: admin_class = ModelAdmin self._registry[model] = admin_class(model, self)
       
       def get_urls(self):
            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'),
                    ]
           
        valid_app_labels = []
        
        for model, model_admin in self._registry.items():#项目启动时会扫描所有app下的admin,此时self._registry中存放的是{Book:BookConfig}
            urlpatterns += [       #设计url
             url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)),
              ]#model._meta.app_label是app的名字,model._meta.model_name是app下面的注册的类名,include(model_admin.urls)又做了路由分发,点进去看urls,其实是看的样式类
ModelAdmin中的urls方法
         return urlpatterns   
        @property    
        def urls(self):        return self.get_urls(), 'admin', self.name
site=AdminSite() #这里的self._registry[model]中的self值的是site,model指的是models.py中的类名,admin_class也就是样式类,admin_class(model, self)中的self也是指的site 
ModelAdmin==>针对某一个model的样式类

URL设计:
  admin的url规范:
    http://127.0.0.1:8000/admin/app01/book/
    http://127.0.0.1:8000/admin/app01/book/add/
    http://127.0.0.1:8000/admin/app01/book/3/change/
    http://127.0.0.1:8000/admin/app01/book/3/delete/
项目的urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),]

 

点进去urls,执行了
 AdminSite类中的
 
def get_urls(self):
    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'),
        ]
        return urlpatterns

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

 





 

源码:
class ModelAdmin(BaseModelAdmin):
  ....
  def __init__(self, model, admin_site):#admin_site指的是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

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



 

 

 


 

posted @ 2018-03-12 23:36  dwenwen  阅读(61)  评论(0)    收藏  举报