zoukankan      html  css  js  c++  java
  • Django——admin源码分析

    在Django中,如果我们新建一个项目,只要在admin.py文件中注册,就可以对其相应的文件进行增删改查操作。

    而我们在路由系统中只看到了一条信息:url(r'^admin/', admin.site.urls),但是我们确实是可以进行增删改查操作?这其中到底有什么端倪了?

    下面我们会从Django源码的角度来分析admin执行流程。

    1.循环加载执行所有已经注册的app中的admin.py文件

    def autodiscover():
        autodiscover_modules('admin', register_to=site)

    2.执行admin.py文件中的代码

    class BookAdmin(admin.ModelAdmin):
        list_display = ("title",'publishDate', 'price')
    
    admin.site.register(Book, BookAdmin) 
    admin.site.register(Publish)

    3.admin.site

    这里应用的是一个单例模式,对于AdminSite类的一个单例模式,执行的每一个app中的每一个admin.site都是一个对象

    4.执行register方法

    admin.site.register(Book, BookAdmin) 
    admin.site.register(Publish)

    register函数源码信息:

    class AdminSite(object):
        ......
            def register(self, model_or_iterable, admin_class=None, **options):
    
            if not admin_class:  #如果没有设置admin_class这个类
                admin_class = ModelAdmin  #那么就会执行默认的样式
    
            if isinstance(model_or_iterable, ModelBase):
                model_or_iterable = [model_or_iterable]
            for model in model_or_iterable:  #在名称列表中循环
                    ......(省略)    
                    self._registry[model] = admin_class(model, self)    #这句话是关键

    执行完admin.site.register()代码之后,就创建_registry这个字典,表名为键,admin_class(样式)为值,我们也可以打印这个字典。

    到这里,注册结束。

    5.admin的URL配置

    上面已经注册成功了,现在该解释URL自动生成的过程了。

    我们先来分析Django源码是如何实现的,从url(r'^admin/', admin.site.urls)出发,我们可以直接找urls函数

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

    随后我们去找get_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):
                def wrapper(*args, **kwargs):
                    return self.admin_view(view, cacheable)(*args, **kwargs)
                wrapper.admin_site = self
                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'),
                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'),
            ]

    关于urlpatterns是如何生成的我们不了解,只知道在这里就生成了增删改查的URL,现在我们用自己的手段来实现这一过程。

    6.自定义实现admin配置

    首先,需要用到路由分发,就像下面这样:

    def test01(request):
        return HttpResponse("test01")
    
    def test02(request):
        return HttpResponse("test02")
    
    def test03(request):
        return HttpResponse("test03")
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^kebi/',([
            url(r'^test01/', test01),
            url(r'^test02/', test02),  #一条URL包含很多条内置的URL,这个部分可以封装到函数中
            url(r'^test03/', test03),
                       ],None,None))
    ]

    里面还可以再次封装,就像这样:

    def test01(request):
        return HttpResponse("test01")
    
    def test0203(request):
        return HttpResponse("test0203")
    
    def test0204(request):
        return HttpResponse("test0204")
    
    def test05(request):
        return HttpResponse("test05")
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^kebi/',([
            url(r'^test01/', test01),
            url(r'^test02/', ([
                url(r'^test03/', test0203),
                url(r'^test04/', test0204),
                              ],None,None)),
            url(r'^test05/', test05),
                       ],None,None))
    ]
    View Code

    我们将其封装到一个函数之中:

    from django.conf.urls import url
    from django.contrib import admin
    from django.shortcuts import HttpResponse
    
    def test01(request):
        return HttpResponse("test01")
    
    def get_urls():
        urlpatterns = []
    
        for model,model_config in admin.site._registry.items():
            model_name = model._meta.model_name  #model可以说是类名,现在要获取字符串拼接,获取类名,属于字符串
            app_label = model._meta.app_label  #app名,属于字符串
            urlpatterns.append(url('%s/%s'%(app_label,model_name),test01))
        return urlpatterns
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^kebi/',(get_urls(),None,None))  #只要urlpatterns有值,就可以做分发
    ]

    这样就生成了:

    http://127.0.0.1:8000/kebi/app02/publish
    http://127.0.0.1:8000/kebi/app01/authors

    仅仅如此,还没有满足要求,那么就在做一次分发,就像这样:

    from django.contrib import admin
    from django.shortcuts import HttpResponse
    
    def show_list(request):
        return HttpResponse("查看列表")
    
    def add_list(request):
        return HttpResponse("增加列表")
    
    def change_list(request,id):
        return HttpResponse("更改列表")
    
    def delete_list(request,id):
        return HttpResponse("删除列表")
    
    def get_urls_func():
        temp = []
        #现在来写增删改查
        temp.append(url('^$',show_list))
        temp.append(url('/add/$',add_list))
        temp.append(url('/(d+)/change/$',change_list))
        temp.append(url('/(d+)/delete/$',delete_list))
    
        return temp
    
    
    def get_urls():
        urlpatterns = []
    
        for model,model_config in admin.site._registry.items():
            model_name = model._meta.model_name  #model可以说是类名,现在要获取字符串拼接
            app_label = model._meta.app_label  #app名
            urlpatterns.append(url('%s/%s'%(app_label,model_name),(get_urls_func(),None,None)))
        return urlpatterns
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^kebi/',(get_urls(),None,None))  #只要urlpatterns有值,就可以做分发
    ]

    现在能够访问的有这些:

    #两个表都会自动生成增删改查的URL
    http://127.0.0.1:8000/kebi/app02/publish
    http://127.0.0.1:8000/kebi/app02/publish/add
    http://127.0.0.1:8000/kebi/app02/publish/1/change
    http://127.0.0.1:8000/kebi/app02/publish/2/delete
    
    http://127.0.0.1:8000/kebi/app01/authors
    http://127.0.0.1:8000/kebi/app01/authors/add
    http://127.0.0.1:8000/kebi/app01/authors/1/change
    http://127.0.0.1:8000/kebi/app01/authors/2/delete

    下面是效果:

     

  • 相关阅读:
    162 基于UDP协议的socket套接字编程
    161 解决粘包问题
    160 粘包问题
    159 模拟ssh远程执行命令
    158 Socket抽象层
    157 基于TCP协议的socket套接字编程
    C++:查找字符串字串并替换
    C++:查找字符串字串并替换
    请问c++中的#include "stdafx.h"是什么意思?
    请问c++中的#include "stdafx.h"是什么意思?
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/8551617.html
Copyright © 2011-2022 走看看