zoukankan      html  css  js  c++  java
  • admin源码解析及自定义stark组件

    admin源码解析

    单例模式

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

    比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

    在 Python 中,我们可以用多种方法来实现单例模式:

    • 使用模块
    • 使用 __new__
    • 使用装饰器(decorator)
    • 使用元类(metaclass)

    (1)使用 __new__

    为了使类只能出现一个实例,我们可以使用 __new__ 来控制实例的创建过程,代码如下:

    class Singleton(object):
        _instance = None
        def __new__(cls, *args, **kw):
            if not cls._instance:
                cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)  
            return cls._instance  
    
    class MyClass(Singleton):  
        a = 1

    在上面的代码中,我们将类的实例和一个类变量 _instance 关联起来,如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance

    执行情况如下:

    >>> one = MyClass()
    >>> two = MyClass()
    >>> one == two
    True
    >>> one is two
    True
    >>> id(one), id(two)
    (4303862608, 4303862608)

    2)使用模块

    其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

    # mysingleton.py
    class My_Singleton(object):
        def foo(self):
            pass
     
    my_singleton = My_Singleton()

    将上面的代码保存在文件 mysingleton.py 中,然后这样使用:

    from mysingleton import my_singleton
     
    my_singleton.foo() # 获得一个单例对象

    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)

    默认admin配置类:ModelAdmin

     注意:admin.site.registry(xx),注册时,_registry{}字典保存的键是model 中的类名,值是model的管理类的AdminClass类

    class ModelAdmin(BaseModelAdmin):pass
    
    def register(self, model_or_iterable, admin_class=None, **options):
        if not admin_class:
                admin_class = ModelAdmin
        # Instantiate the admin class to save in the registry
        self._registry[model] = admin_class(model, self)

    那么,在app的stark.py中加上(同理可在每一个app的admin.py中测试)

    print(site._registry)   # stark.py,执行结果?
    print(admin.site._registry)   # admin.py,执行结果?

    结果:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time    : 2018/07/23 9:53
    # @Author  : MJay_Lee
    # @File    : stark.py
    # @Contact : limengjiejj@hotmail.com
    
    from app01 import models
    from stark.service.stark import site,ModelStark
    from django.utils.safestring import mark_safe
    
    class BookConfig(ModelStark):
    
        list_display = ["title","price","publish"]
    
    site.register(models.Book,BookConfig)
    
    site.register(models.Author)
    site.register(models.AuthorDetail)
    site.register(models.Publish)
    
    print("my_stark.app01===>
    ",site._registry)
    # 打印结果
    '''
    my_stark.app01===>
     {<class 'app01.models.Book'>: <app01.stark.BookConfig object at 0x0000018D0A372748>, <class 'app01.models.Author'>: <stark.service.stark.ModelStark object at 0x0000018D0A372A58>, <class 'app01.models.AuthorDetail'>: <stark.service.stark.ModelStark object at 0x0000018D0A372AC8>, <class 'app01.models.Publish'>: <stark.service.stark.ModelStark object at 0x0000018D0A37D1D0>}
    '''
    打印结果

    到这里,注册结束!

     <5> admin的URL配置

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    ]

    如何实现路由分发:

    class AdminSite(object):
        
         def get_urls(self):
            from django.conf.urls import url, include
          
            urlpatterns = []
    
            # Add in each model's views, and create a list of valid URLS for the
            # app_index
            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

    <6>  url()方法的扩展应用

    from django.shortcuts import HttpResponse
    def test01(request):
        return HttpResponse("test01")
    
    def test02(request):
        return HttpResponse("test02")
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^yuan/', ([
                        url(r'^test01/', test01),
                        url(r'^test02/', test02),
    
                        ],None,None)),
    
    ]

    扩展优化

    from django.conf.urls import url,include
    from django.contrib import admin
    
    from django.shortcuts import HttpResponse
    
    def change_list_view(request):
        return HttpResponse("change_list_view")
    def add_view(request):
        return HttpResponse("add_view")
    def delete_view(request):
        return HttpResponse("delete_view")
    def change_view(request):
        return HttpResponse("change_view")
    
    def get_urls():
    
        temp=[
            url(r"^$".format(app_name,model_name),change_list_view),
            url(r"^add/$".format(app_name,model_name),add_view),
            url(r"^d+/del/$".format(app_name,model_name),delete_view),
            url(r"^d+/change/$".format(app_name,model_name),change_view),
        ]
    
        return temp
    
    
    url_list=[]
    
    for model_class,obj in admin.site._registry.items():
    
        model_name=model_class._meta.model_name
        app_name=model_class._meta.app_label
    
        # temp=url(r"{0}/{1}/".format(app_name,model_name),(get_urls(),None,None))
        temp=url(r"{0}/{1}/".format(app_name,model_name),include(get_urls()))
        url_list.append(temp)
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^yuan/', (url_list,None,None)),
    ]

    stark组件开发

    仿照Django内置的admin组件自定义一个后台管理组件,实现数据的CRUD

    准备工作

    首先,我们需要新建一个Django项目,一个方便组织代码的APP应用,一个stark APP用于存放自定义组件的核心代码。

    创建成功之后到settings.py文件对app进行注册

    启动

    在stark应用下的apps.py文件添加一下代码,加载每一个app下的所有stark文件

    from django.apps import AppConfig
    from django.utils.module_loading import autodiscover_modules
    
    
    class StarkConfig(AppConfig):
        name = 'stark'
    
        # 在项目启动的时候加载所有的stark模块
        def ready(self):
            autodiscover_modules('stark')

    注册

    我们在使用Django内置的admin组件的时候,首先就是要对我们创建的Model(模型表)进行注册,至于注册过后我们才可以对表的数据进行CRUD操作。

    首先,创建一个Python Package包,创建一个stark文件

    正如本篇开头所述,我们在使用admin组件的时候,是在我们注册时候调用一个单例对象site进行注册

    class StarkSite(object):
            def __init__(self):
                self._registry = {}
    
    site = StarkSite()

    然后在app01的stark文件中导入

    from stark.service.stark import site

    生成一个单例对象

    通过单例对象site调用注册方法,所以需要在StarkSite类创建一个register方法

    # servicestark.py
    def
    register(self, model, admin_class=None, **options): # 如果注册的时候没有自定义配置类,执行 if not admin_class: admin_class = ModelStark # 配置类 # 将配置类对象加到_registry字典中,键为模型类 self._registry[model] = admin_class(model) # _registry={'model':admin_class(model)}

    在对应app中的注册方法:

    # app01stark.py
    
    
    from app01 import models
    from stark.service.stark import site,ModelStark
    
    # 自定义配置类
    class BookConfig(ModelStark):
        pass
    
    site.register(models.Book,BookConfig)
    site.register(models.Author)
    site.register(models.AuthorDetail)
    site.register(models.Publish)

    注册之后,启动项目就会将我们注册的模型类添加到字典_registry中

    设计URL

    Django项目建起来之后就会自动创建一个url文件,如:其中admin的url就已经配置好了

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    ]

    进入源码看一眼,会发现url方法有property装饰器,会将函数装饰成一个属性

    它会在项目的启动的时候就执行,将内部的url进行分发,生成url的方法就是get_urls()

    自定义url

    def get_urls(self):
            temp = []
            for model,config_obj in self._registry.items():
                model_name = model._meta.model_name # 拿到模型类的名字
                app_label = model._meta.app_label # 拿到当前类所在app的名字
                # 第一路由
                temp.append(url(r'^%s/%s/'%(app_label, model_name),config_obj.urls))
    
            return temp
    
        @property
        def urls(self):
            return self.get_urls(),None,None

    这样就可以对每一个app下面的每一个模型类进行url分发,但是还要对每一个模型进行数据的增删改查,所以就需要进行第二级的分发

    二级url分发实现:

    def get_urls(self):
        temp = []
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
    
        temp.append(url("^$", self.list_view,name="%s_%s_list"%(app_label,model_name)))
        temp.append(url("^add/$",self.add_view,name="%s_%s_add"%(app_label,model_name)))
        temp.append(url("^(d+)/change/",self.change_view,name="%s_%s_change"%(app_label,model_name)))
        temp.append(url("^(d+)/delete/",self.delete_view,name="%s_%s_delete"%(app_label,model_name)))
        return temp
    
    @property
    def urls(self):
    
        return self.get_urls(),None,None
  • 相关阅读:
    mysql命令集锦
    linux 删除文件名带括号的文件
    linux下的cron定时任务
    struts2文件下载的实现
    贴一贴自己写的文件监控代码python
    Service Unavailable on IIS6 Win2003 x64
    'style.cssText' is null or not an object
    "the current fsmo could not be contacted" when change rid role
    远程激活程序
    新浪图片病毒
  • 原文地址:https://www.cnblogs.com/limengjie0104/p/9355669.html
Copyright © 2011-2022 走看看