admin.py

 
from django.contrib import admin
from . import models
"""
通过原生的django admin来创造数据
"""
admin.site.register(models.User)
admin.site.register(models.Role)
admin.site.register(models.Permission)
admin.site.register(models.Group)
admin.site.register(models.Menu)
 

url.py

 
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
]
 

以上两个文件都引用的是django.contrib.admin.site中的方法,site是AdminSite实例化出来的一个对象,所以site调用的register方法和urls属性(方法被@property装饰器装饰)是AdminSite这个类中定义的

django启动的时候,顺序为:先register,然后在urls分配

先看admin.site.register干了什么

在源码AdminSite这个类的构造方法初始化定义了一个空字典 _registry={}

1
2
3
4
5
6
7
8
class AdminSite(object):
    ...
    def __init__(self, name='admin'):
        self._registry = {}  # model_class class -> admin_class instance
        self.name = name
        self._actions = {'delete_selected': actions.delete_selected}
        self._global_actions = self._actions.copy()
        all_sites.add(self)

看源码中的admin.site.register函数如下

 
    def register(self, model_or_iterable, admin_class=None, **options):
"""
Registers the given model(s) with the given admin class. The model(s) should be Model classes, not instances. If an admin class isn't given, it will use ModelAdmin (the default
admin options). If keyword arguments are given -- e.g., list_display --
they'll be applied as options to the admin class. If a model is already registered, this will raise AlreadyRegistered. If a model is abstract, this will raise ImproperlyConfigured.
"""
if not admin_class:
admin_class = ModelAdmin if isinstance(model_or_iterable, ModelBase):
model_or_iterable = [model_or_iterable]
for model in model_or_iterable:
if model._meta.abstract:
raise ImproperlyConfigured(
'The model %s is abstract, so it cannot be registered with admin.' % model.__name__
) if model in self._registry:
raise AlreadyRegistered('The model %s is already registered' % model.__name__) # Ignore the registration if the model has been
# swapped out.
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) # Instantiate the admin class to save in the registry
self._registry[model] = admin_class(model, self)
 

register函数第一个参数是注册的模块名称,第二个参数不传默认是None,但是实际使用的是ModelAdmin,ModelAdmin已模块名称作为参数实例化得到的对象作为 registry字典的value。简化如下:

 
def register(self, model_or_iterable, admin_class=None, **options):
if not admin_class:
admin_class = ModelAdmin for model in model_or_iterable:
.......
.......
self._registry[model] = admin_class(model, self)
 

再看admin.site.urls干了什么

源码精简如下:

 
def get_urls(self):
from django.conf.urls import url, include
from django.contrib.contenttypes import views as contenttype_views def wrap(view, cacheable=False):
......
return update_wrapper(wrapper, view) # Admin-site-wide views.
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'),
......
] 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 @property
def urls(self):
return self.get_urls(), 'admin', self.name #返回的是一个元组
 

首先urls是个函数被@property装饰器装饰为属性,urls属性返回的是一个元组【元组的第一个元素是列表,由get_urls函数返回】

get_urls函数中定义了一个urlpatterns并最终返回,里面有url路径和视图函数的对应关系,这些默认register(admin)后自带的,所以在urls.py 执行

1
url(r'^admin/', admin.site.urls)   

会找到注册的admin类,为每一个类生成N个URL(如上urlpattern中定义的)

如果用户自己注册的模块,如下

1
admin.site.register(models.UserInfo) # 注册的时候没有传入admin_class,默认使用的是ModelAdmin 

会根据下面的代码添加到urlpatterns中

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)),
]

model_class._meta.app_label 代表model所在的模块名比如app01
model_class._meta.model_name 代表model对应的表的小写名,比如userinfo

这样就生成了/app01/userinfo/ 这样的url前缀。

后面调用的include(model_admins.urls) 中的model_admins.urls 即执行的是self._registry['UserInfo'].urls ===== admin_class(model, self).urls=======admin_class这个类生成对象的urls属性【此时这个对象是UserInfo的对象,所以下面get_url函数中的self指的就是UserInfo的对象】======admin_class这个类的urls属性========= > ModelAdmin这个类的urls属性【因为注册的时候没有传入admin_class,所以默认是ModelAdmin】

再来看下ModelAdmin这个类的urls属性

 
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), # self代表的是UserInfo的对象
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()
 

同理,urls是个被@property装饰的属性,调用ModelAdmin类自身的get_urls函数的时候返回的即是上面红色的urlpatterns【这也是django admin为什么注册了一个类之后就为这个类提供了基本url和函数映射的基本原因】,这样和上面形成的url路径拼接即可得到如下的效果

urlpatterns = [
url(r'admin/app01/userinfo/', wrap(self.changelist_view), name='%s_%s_changelist' % info),
url(r'admin/app01/userinfo/add/$', wrap(self.add_view), name='%s_%s_add' % info), # self 代表的是UserInfo
url(r'admin/app01/userinfo/(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info),
url(r'admin/app01/userinfo/(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info),
url(r'admin/app01/userinfo/(.+)/change/$', wrap(self.change_view), name='%s_%s_change' % info),
# For backwards compatibility (was the change url before 1.9)
url(r'admin/app01/userinfo/(.+)/$', wrap(RedirectView.as_view(
pattern_name='%s:%s_%s_change' % ((self.admin_site.name,) + info)
))),
]

当然也可以自定制ModelAdmin,如下

 
from django.contrib import admin
from django.contrib.admin import ModelAdmin
from . import models
from django.shortcuts import HttpResponse class UserInfoModelAdmin(ModelAdmin):
# 没有__super__ 是这个类只定义了一个方法,没有继承其他的?还是继承了所有,只覆盖了这一个呢?
# 自定义功能
def changelist_view(self, request, *args,**kwargs):
return HttpResponse('用户列表') admin.site.register(models.UserInfo,UserInfoModelAdmin)
class UserTypeModelAdmin(ModelAdmin):
pass admin.site.register(models.UserType,UserTypeModelAdmin)
 

继承自ModelAdmin,并重写了changelist_view 这个方法,父类 其他的继承了吗?==

所以上面这张register的方法可以如下理解:

 
在admin.site对象的 _registry = {}
_registry = {
models.UserInfo: obj1 = ModelAdmin(models.UserInfo,admin.site), #obj1 即上面说的UserInfo对象
/admin/app01/userinfo/ obj1.changelist_view
/admin/app01/userinfo/add/ obj1.add_view
/admin/app01/userinfo/(\d+)/delete/ obj1.delete_view
/admin/app01/userinfo/(\d+)/change/ obj1.change_view
self.model=models.UserInfo models.UserType: obj2 = ModelAdmin(models.UserType,admin.site), #obj2 和上面说的同理,代表的是UserType对象
/admin/app01/usertype/ obj2.changelist_view
/admin/app01/usertype/add/ obj2.add_view
/admin/app01/usertype/(\d+)/delete/ obj2.delete_view
/admin/app01/usertype/(\d+)/change/ obj2.change_view
self.model=models.UserType
} 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)),
url(r'^%s/%s/' % ('app01', 'userinfo'), include(model_admin.urls)),
]
 

Django--admin源码流程的更多相关文章

  1. Django session 源码流程

    流程 Django session源码流程 首先执行的是SessionMiddleware的init方法 import_module(settings.SESSION_ENGINE) 导入了一个 dj ...

  2. django -admin 源码解析

    admin源码解析 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单 ...

  3. Django——admin源码分析

    在Django中,如果我们新建一个项目,只要在admin.py文件中注册,就可以对其相应的文件进行增删改查操作. 而我们在路由系统中只看到了一条信息:url(r'^admin/', admin.sit ...

  4. Django admin源码剖析

    单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...

  5. django-admin的源码流程

    一.admin的源码流程 首先可以确定的是:路由关系一定对应一个视图函数 a.当点击运行的时候,会先找到每一个app中的admin.py文件,并执行 b.执行urls.py admin.site是什么 ...

  6. Django admin组件源码流程

    admin 组件 Django 自带的用户后台组件 用于用户便携的操作 admin 组件核心 启动 注册 设计url 启动核心代码 每个app 通过 apps.py 扫描 admin.py 文件 并执 ...

  7. django之admin源码解析

    解析admin的源码 第一步:项目启动,加载settings文件中的 INSTALLED_APPS 里边有几个app就加载几个,按照注册顺序来执行. 第二步:其中加载的是admin.py,加载每一个a ...

  8. Django Rest Framework框架源码流程

    在详细说django-rest-framework源码流程之前,先要知道什么是RESTFUL.REST API . RESTFUL是所有Web应用都应该遵守的架构设计指导原则. REST是Repres ...

  9. Django drf:序列化增删改查、局部与全局钩子源码流程、认证源码分析、执行流程

    一.序列化类的增.删.改.查 用drf的序列化组件   -定义一个类继承class BookSerializer(serializers.Serializer):   -写字段,如果不指定source ...

  10. admin源码解析及自定义stark组件

    admin源码解析 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单 ...

随机推荐

  1. PHP 使用redis实现秒杀

    PHP 使用redis实现秒杀 使用redis队列,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用(mysql事务在高并发下性能下降很厉害,文件锁的方式也是) 先将商品库存如队 ...

  2. spring aop 动态代理批量调用方法实例

    今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常.因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候 ...

  3. 阿里云服务器部署php的laravel项目,在阿里云买ECS 搭建 Linux+Nginx+Mysql+PHP环境的

    在阿里云买ECS的时候选择自己习惯的镜像系统,我一般都是使用Linux Ubuntu,所以,以下的配置都是在Ubuntu 14.04稳定支持版的环境中搭建Linux+Nginx+Mysql+PHP环境 ...

  4. 使用questionsModel.values()后不能获取模型中的属性对应的外键属性值的解决方式

    class QuestionsModel(models.Model): author = models.ForeignKey(FrontUserModel,null=True) content = m ...

  5. 转自知乎-wifi破解

    上点python有意思的代码. 环境准备 python2.7 pywifi模块 字典 清除系统中的任何wifi连接记录 导入模块 这里用的模块就这三个 pywifi的_wifiutil_linux.p ...

  6. iOS日历中给一个事件加入多个提醒

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 假设认为写的不好请多提意见,假设认为不错请多多支持点赞.谢谢! hopy ;) iOS自带的日历应用中,我们最多仅仅能给一个事件设置2个提醒, ...

  7. POJ - 1611The Suspects-并查集

    POJ - 1611 The Suspects Time Limit: 1000MS   Memory Limit: 20000KB   64bit IO Format: %I64d & %I ...

  8. .NET Core 已经实现了PHP JIT,现在PHP是.NET上的一门开发语言

    12月23日,由开源中国联合中国电子技术标准化研究院主办的2017源创会年终盛典在北京万豪酒店顺利举行.在本次大会上,链家集团技术副总裁.PHP 开发组核心成员鸟哥发表了以 " PHP Ne ...

  9. 基于MATLAB的人脸识别算法的研究

    基于MATLAB的人脸识别算法的研究 作者:lee神 现如今机器视觉越来越盛行,从智能交通系统的车辆识别,车牌识别到交通标牌的识别:从智能手机的人脸识别的性别识别:如今无人驾驶汽车更是应用了大量的机器 ...

  10. F12调试模式下使用console自动提交

    F12调试模式下使用console自动提交(F12 的console->输入代码->按enter即可运行) 1.使用定时器setInterval进行自动提交 //方法中可使用jquery调 ...