Django 【第二十五篇】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 )
            

原文地址:https://www.cnblogs.com/xiaohema/p/8456644.html

时间: 2024-11-10 03:41:16

Django 【第二十五篇】Django admin源码解析的相关文章

spring boot实战(第十五篇)嵌入tomcat源码分析

嵌入tomcat源码分析 在启动spring boot工程时利用@SpringBootApplication注解,该注解启动@EnableAutoConfiguration自动配置,加载META-INF/spring.factories文件 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.boot.autoconfigure.admin.Spri

Egret入门学习日记 --- 第二十五篇(书中 9.16~9.17 节 内容)

第二十五篇(书中 9.16~9.17 节 内容) 对于昨天的关于 List 组件使用的问题,我打算到书中提到List之后,再回头补充. 还有就是 Scroller 的 TileLayout 布局方式,也要去研究一下. 好了,开始按照书中内容一步一步走. 开始 9.16节. 重点: 1.设定TabBar皮肤. 2.设置TabBar布局. 操作: 1.设定TabBar皮肤. 第一步,准备素材! 第二步,创建 exml 文件! 第三步,拖入组件!约束大小! 第四步,增加两个状态 down 和 up.

ExcelReport第二篇:ExcelReport源码解析

导航 目   录:基于NPOI的报表引擎--ExcelReport 上一篇:使用ExcelReport导出Excel 下一篇:扩展元素格式化器 概述 针对上一篇随笔收到的反馈,在展开对ExcelReport源码解析之前,我认为把编写该组件时的想法分享给大家是有必要的. 编写该组件时,思考如下: 1)要实现样式.格式与数据的彻底分离. 为什么要将样式.格式与数据分离呢?恩,你不妨想一想在生成报表时,那些是变的而那些又是不变的.我的结论是:变的是数据. 有了这个想法,很自然的想到用模板去承载不变的部

第二十五篇 jQuery 学习7 获取并设置 CSS 类

jQuery 学习7 获取并设置 CSS 类 jQuery动态控制页面,那么什么是动态呢?我们就说一下静态,静态几乎又纯html+css完成,就是刷新页面之后,不会再出现什么变动,一个实打实的静态页面.那么动态,我们基于静态的特征说,动态:刷新页面之后,还可以发生样式改变等,就为动态. 这节课我们学习的是jQuery控制css,那么css样式都被改变了,算动态么?当然算啦,刷新页面之后发生了改变,就已经不是静态了,只要是变动了,就算是啦. 我们这节课学习四个控制css的方法: addClass(

第37篇 Asp.Net源码解析(二)--详解HttpApplication

这篇文章花了点时间,差点成烂到电脑里面,写的过程中有好几次修改,最终的这个版本也不是很满意,东西说的不够细,还需要认真的去看下源码才能有所体会,先这样吧,后面有时间把细节慢慢的再修改.顺便对于开发的学习,个人是觉得源码的阅读是最快的提高方式,当然阅读不是走马观花,应该多次阅读. 上次说到获得HttpApplication对象的创建,创建完成后调用InitInternal方法,这个方法任务比较多,也比较长,这里就不贴全码了,一个一个过程的去说: 初始化HttpModule 对于HttpModule

【Python之路】第二十二篇--Django【基础篇】

1 Django流程介绍 MTV模式       著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层:他们之间以一种插件似的,松耦合的方式连接在一起. 模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求. Django的MTV模式本质上与MVC模式没有什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同,Django的MTV分别代表: Model(模型):负责业务对象与数

第二十五篇 苦逼的人生该作何解释

今天我遇到了一些问题,这是一些生活中的情感问题,要是谁有好的方法,能不能为我指点一下迷津...... 原本今天的心情就像今天的天气一样,风和日丽,景色花香,日子还是过的很潇洒,又有小伙伴们一起娱乐.一起玩耍.但是下午突如其来的 一个电话 打破了这种和谐的景象,是什么电话呢,来自我爸手机上的一条短信,大概内容就是  要 确定是否为我的学费做出担保,其中的含义我就不多说了,反正一句话很简单------要钱,于是他马上打了一通电话给我,说这是什么情况:而我爸的脾气又火爆,我虽然性子特温顺,但是放到他身

python全栈开发基础【第二十五篇】死锁,递归锁,信号量,Event事件,线程Queue

一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程, 如下就是死锁 #死锁现象 死锁------------------- from threading import Thread,Lock,RLock import time mutexA = Lock() mutexB = Lock() class

第二十五篇:在SOUI中做事件分发处理

不同的SOUI控件可以产生不同的事件.SOUI系统中提供了两种事件处理方式:事件订阅 + 事件处理映射表(参见第八篇:SOUI中控件事件的响应) 事件订阅由于直接将事件及事件处理函数连接,不存在事件分发的问题,这里主要介绍使用事件映射表时的事件分发. 在回答这个问题前,首先了解一下什么是事件分发. 在大型项目中,程序逻辑可能非常复杂,如果将所有UI中控件的事件处理集中在一个消息/事件映射表里,代码的可维护性会变得非常差.解决这个问题常见的方法就是将事件进行分类(如根据来源分类),不同类别的事件采