Django--admin源码流程

 

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

 

转载于:https://www.cnblogs.com/huchong/p/8034649.html

功能简介: 1、移动考勤:移动互联网时代的打卡利器,基于地理位置定位识别,员工通过微信可以快速完成签到,全面取代传统的打卡、指纹签到系统,企业无需额外购置考勤系统;针对外勤人员管理,可通过上报地理位置来实时监督,系统自动形成团队成员的工作考勤轨迹。 2、投票:多样化的投票类型,可预设的定时投票,直观的投票详情,随时随地看到您参与投票的各选项比例,数据结果更有价值。 3、报销:化繁为简,审批进度一目了然,结果及时提醒,报销单随时打印,类型自由设置。 4、流程审批:审批流程完全自定义、审批人员自由配置,满足您个性化的流程审批需求。 5、任务协作:任务管理应用,轻松安排您与团队每一天的工作分派,实时掌握工作进度,有效提高您和团队的工作效率。 6、调研:实时收集来自团队的宝贵意见,数据分析直观明了,自动生成图形分析报表,有效提高您的调研质量。 7、招聘:让一群小小HR在微信6亿用户中,帮企业搜寻符合招聘要求的潜在求职者。 悬赏小小红包,即可征集一群真实卖力的HR利用社交关系发散传播,投递简历手机号必须验证,收到简历会直接推送给推荐员工,让推荐人对此简历进行评价,这含金量高达99.9%啊!员工推荐好友,世界上没有比这更靠谱的招聘啦! 8、请假:无论身处何处,通过微信即可发起请假申请,并且可以抄送相关人员;请假申请、审批结果等信息将以微信消息的形式实时到达领导/老板的手机,让管理者灵活方便的处理员工的请假申请。 9、微名片:创建个性名片,收纳海量好友,是一款时尚又新潮,简单又好用的电子名片管理应用。在我的名片夹中建立分组,按照分组将不同的名片进行归类,高效管理和使用名片,可以向给您发送名片的客户及朋友一键回赠名片,并可将名片信息高效的转发给其它朋友,根据您的喜好,挑选自己心爱的名片模板。 创建个性名片,收纳海量好友,是一款时尚又新潮,简单又好用的电子名片管理应用。拥有微名片,无须因联系信息变更而通知大量好友而烦恼。无须携带大量纸质名片,方便环保,高效地管理您的人脉资源. 10、会议室预定:高效的会议室预定管理应用,实现可以通过微信完成会议室查询、会议室预订、会议签到、会议记录/会议纪要等。解决您烦恼的会议室预定管理问题。 11、日程管理:全体员工的随身记事本,大家随时在微信上快速记录备忘信息到日程管理,支持多次编辑。同时,用户可以将日程管理的信息分享给同事、领导或任何相关人,进行团队协作,是您移动化办公的有效武器。 12、微信外勤:时下最流行的考勤形式,高效掌控员工出勤状况。提供外勤签到打卡、客户拜访汇报,随时微信上提交客户拜访信息(包括拜访内容、拜访对象、拜访地点),并发送给指定人随时创建外勤工单,向领导汇报或请示,领导可以向属下分派外勤任务。 13、企业公告:企业发布公司最新通知、动态、公告的平台。无论身处何地,随时发布公告,可设置消息保密和阅读范围,微信消息实时提醒,公告消息永不落空;支持菜单类型自定义和模板选择,发布公告更省心。 14、企业知识库:公司文档,打开微信随时随地想查就查,可对文档点赞、反馈,支持离线阅读,统计数据、反馈等信息,后台清晰可见. 15、离职:可以通过微信快速办理离职手续,方便快捷。 16、借书:打破了传统图书馆借书的模式,物流免费上门送取的全新借书模式,让用户可以足不出户,便可用借阅到最新、最畅销、最经典的纸质图书。 17、聊天室:以社交、办公、娱乐为主题,成立以贯彻文明聊天、娱乐的原则,开发一系列娱乐、办公的服务工具。 18、工作日志:详细记录所面对的选择、观点、方法、结果和决定,每天日事日清,长期的积累,达到通过工作日志提高自己的工作技能。 19、售后:是一种质量的保证,一种信任,微易科技开启了用微信来完成售后的申请 20、在线考试:通过微信上进行考试整个过程的一种考试形式,脱离了传统的纸质媒体形式,提供企业或者学校在线考试等服务。 21、绩效:促进公司内部人员的互动,增强人际交流;激励员工,提高公司绩效;有利于绩效周期总结,同时可以制定新的福利政策,激励员工不断积极进取;一个总结和提高的过程,实现企业的战略目标。 22、进销存:轻松录入数据,放心等待结果,让产品的库存统计更加实时,准确,让日常工作的分工更加清晰和科学,减少企业的会计与业务员的人工投入,降低对工作人员的要求,加快会计工作速度,并及时、准确地提供更多、更全面的管理信息。 注:数据库需手动导入,然后修改Data\Conf\db.php中的相关数据即可。 环境:PHP/Mysql 管理后台:在域名后面添加 yi.php 即可 账户密码:admin 目前第五卷 分卷上传共五卷,下卷在下篇文章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值