django-admin的源码流程

Posted maaosheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django-admin的源码流程相关的知识,希望对你有一定的参考价值。

 一、admin的源码流程

首先可以确定的是:路由关系一定对应一个视图函数

a、当点击运行的时候,会先找到每一个app中的admin.py文件,并执行

b、执行urls.py 

admin.site是什么?

admin.site,urls    返回的是一个元组,里面的第一个元素是一个列表

技术图片
django-admin的源码流程
我们自己生成的动态的访问url
====================================初级版=========================
from django.shortcuts import HttpResponse
from django.conf.urls import url
from django.contrib import admin
from app01 import views
def login(request):
    return HttpResponse("ok")

url_list = []

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的名称
    val = url(r^0/1/$.format(app_name,cls_name), login, name="login")
    url_list.append(val)

urlpatterns = [
    url(r^admin/, admin.site.urls),
    # admin.site这个对象里面有一个属性_registry = 
    #点击urls查看源码返回的是一个元组,元组的第一个元素是一个列表
    url(r^index/, ([
            url(r^app01/userinfo/$, login,name="login"),
             url(r^app01/roles/$, login,name="login"),
        ],None,None)),
        
    url(r^index2/, (url_list,None,None,)),  #吧上面定义的列表拿下来,这是后就动态生成了
]
技术图片
技术图片
================================升级============================
路径http://127.0.0.1:8001/index/app01/roles/后面还有增删改查的路径
http://127.0.0.1:8001/index/app01/roles/add/
http://127.0.0.1:8001/index/app01/roles/1/change/
http://127.0.0.1:8001/index/app01/roles/1/del/

实现流程
from django.shortcuts import HttpResponse
from django.conf.urls import url
from django.contrib import admin
from app01 import views
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("删除页面")

url_list = []

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 = url(r^0/1/$.format(app_name,cls_name), change_list, name="login")
    url_list.append(urls_list)

    add_url = url(r^0/1/add/$.format(app_name, cls_name), add_view, name="login")
    url_list.append(add_url)

    change_url = url(r^0/1/(\\d+)/change/$.format(app_name, cls_name), change_view, name="login")
    url_list.append(change_url)

    del_url = url(r^0/1/(\\d+)/del/$.format(app_name, cls_name), delete_view, name="login")
    url_list.append(del_url)

urlpatterns = [
    url(r^admin/, admin.site.urls),
    # admin.site这个对象里面有一个属性_registry = 
    #点击urls查看源码返回的是一个元组,元组的第一个元素是一个列表
    url(r^index/, (
        [
            url(r^app01/userinfo/$, login,name="login"),
            url(r^app01/roles/$, login,name="login"),
         ],None,None)),
    url(r^index2/, (url_list,None,None,)),  #吧上面定义的列表拿下来,这是后就动态生成了
]

说明了:
    url的本质:它读取_registry所有字典里面的数据,为字典里面的每一个类生成了4个url
技术图片
技术图片
==================================修改上面的版本=============================
定义了一个
def get_urls():
    temp = [
        url(r^$.format(app_name, cls_name), change_list),
        url(r^add/$.format(app_name, cls_name), add_view),
        url(r^del/$.format(app_name, cls_name), delete_view),
        url(r^change/$.format(app_name, cls_name), change_view)
    ]
    return temp
    
url_list = []
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的名称
    方式一:
    # all_urls = url(r‘^0/1/‘.format(app_name,cls_name), (get_urls(),None,None,))
    方式二:
    all_urls = url(r^0/1/.format(app_name,cls_name), include(get_urls()) )   
    url_list.append(all_urls)

    
urlpatterns = [
    url(r^admin/, admin.site.urls),
    # admin.site这个对象里面有一个属性_registry = 
    #点击urls查看源码返回的是一个元组,元组的第一个元素是一个列表
    url(r^index/, (
        [
            url(r^app01/userinfo/, ([
                                           url(r^$, change_list, name="login"),
                                           url(r^add/$, add_view, name="login"),
                                           url(r^(\\d+)/del/$, delete_view, name="login"),
                                           url(r^(\\d+)/change/$, change_view, name="login"),
                                       ],None,None),name="login"),
            url(r^app01/usertype/, ([
                                           url(r^$, change_list, name="login"),
                                           url(r^add/$, add_view, name="login"),
                                           url(r^(\\d+)/del/$, delete_view, name="login"),
                                           url(r^(\\d+)/change/$, change_view, name="login"),
                                       ], None, None), name="login"),],None,None)),
            url(r^app02/article/, ([
                                           url(r^$, change_list, name="login"),
                                           url(r^add/$, add_view, name="login"),
                                           url(r^(\\d+)/del/$, delete_view, name="login"),
                                           url(r^(\\d+)/change/$, change_view, name="login"),
                                       ],None,None),name="login"),

    # index和index2的两个是一样的,我们可以用index2的方式替代index
    url(r^index2/, (url_list,None,None,)),  #吧上面定义的列表拿下来,这是后就动态生成了
]


include的本质就是:返回了一个元组,元组的第一个是这个模块
include里面
    既可以写一个列表include([]),利用include做分发
    也可以返回一个字符串:帮我们去找到这个模块,找到所有的映射关系

include(model_admin.urls)
model_admin是什么?ModelAdmin对象的urls
技术图片

总结

技术图片
- 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():
                        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 )
            
技术图片

 

以上是关于django-admin的源码流程的主要内容,如果未能解决你的问题,请参考以下文章

vlc源码分析 播放流程

dhcp1.0源码分析,讲解dhcpd的源码流程。

Django-admin用法和源码分析

Django 第二十五篇Django admin源码解析

如何使用邮递员从 keycloak 获取访问令牌(授权码流)

vlc播放流程分析