stark组件之注册与路由系统

在文章stark组件前戏中已经提到过,django的注册功能是通过AdminSite的单例进行组册的,所以在这里也可以进行单例模式。

class AdminSite(object):

    def __init__(self):
        self._registry=[]
        self.app_name='stark'
        self.namespace='stark'

    def register(self,model_class,stark_class=None,prev=None):
       
        if not stark_class:
            stark_class=BaseStark

        self._registry.append(ModelStarkMapping(model_class,stark_class(model_class,self,prev),prev))
        #self._registry.append({'model':model_class,'stark_class':stark_class(model_class,self,prev),prev})
        # for k,v in self._registry.items():
        #     print(k,v)0
        """
    之前
_registry={ 'UserInfo':BaseStark(UserInfo,site) 封装UserInfo类和site 'Role':RoleStark(Role,site) 封装 Role类和site } """ def get_urls(self): urlpatterns=[] for item in self._registry: #循环得到的是每一个ModelStarkMapping对象 app_label=item.model_class._meta.app_label model_name=item.model_class._meta.model_name if item.prev: temp = path('%s/%s/%s/' % (app_label, model_name,item.prev), (item.stark_class.urls, None, None)) else: temp = path('%s/%s/' % (app_label, model_name,), (item.stark_class.urls, None, None)) urlpatterns.append(temp) return urlpatterns @property def urls(self): return self.get_urls(),self.app_name,self.namespace

可以看到之前_registry是一个字典,现在变成了一个列表,为什么要这样做呢?

(1)这是因为如果是字典的话,一个model只能注册一次,现在是model可以注册多次,只需要将model对应的类按照需要表换,这样在一个页面上来实现一个model不同的数据展示。

(2)pre前缀的功能是为了将不同model注册的url加以区别,如下所示:

site.register(models.Customer,PersonalCustomerStark,'per')
site.register(models.Customer,CustomerStark)

另外将一个个字典的内容封存为一个对象,这样取值方便,当然,字典也是没问题的。

class ModelStarkMapping(object):

    def __init__(self,model_class,stark_class,prev):
        self.model_class=model_class
        self.stark_class=stark_class
        self.prev=prev

这就是注册功能的实现过程,接下来就是路由系统的构建。

可以看到上述在返回urlpatterns列表时,第二个元素是三个参数组成的元组,按理说应该是include()进行二级路由分发才对呀,其实这是include()方法的本质,在include()方法中返回的就是这么三个参数的元组。

def include(arg, namespace=None):
    app_name = None
    if isinstance(arg, tuple):
        # Callable returning a namespace hint.
        try:
            urlconf_module, app_name = arg
        except ValueError:
            if namespace:
                raise ImproperlyConfigured(
                    'Cannot override the namespace for a dynamic module that '
                    'provides a namespace.'
                )
            raise ImproperlyConfigured(
                'Passing a %d-tuple to include() is not supported. Pass a '
                '2-tuple containing the list of patterns and app_name, and '
                'provide the namespace argument to include() instead.' % len(arg)
            )
    else:
        # No namespace hint - use manually provided namespace.
        urlconf_module = arg

    if isinstance(urlconf_module, str):
        urlconf_module = import_module(urlconf_module)
    patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module)
    app_name = getattr(urlconf_module, 'app_name', app_name)
    if namespace and not app_name:
        raise ImproperlyConfigured(
            'Specifying a namespace in include() without providing an app_name '
            'is not supported. Set the app_name attribute in the included '
            'module, or pass a 2-tuple containing the list of patterns and '
            'app_name instead.',
        )
    namespace = namespace or app_name
    # Make sure the patterns can be iterated through (without this, some
    # testcases will break).
    if isinstance(patterns, (list, tuple)):
        for url_pattern in patterns:
            pattern = getattr(url_pattern, 'pattern', None)
            if isinstance(pattern, LocalePrefixPattern):
                raise ImproperlyConfigured(
                    'Using i18n_patterns in an included URLconf is not allowed.'
                )
    return (urlconf_module, app_name, namespace)
include()

然后可以看看二级路由,在BaseStark这个基类中定义了二级路由。

...   
def get_urls(self): urlpatterns = [ re_path('list/$', self.wrapper(self.changelist_view), name=self.get_list_url_name ), re_path('add/$', self.wrapper(self.add_view), name=self.get_add_url_name), re_path('(?P<pk>\d+)/change/$', self.wrapper(self.change_view), name=self.get_edit_url_name), re_path('(?P<pk>\d+)/del/$', self.wrapper(self.del_view), name=self.get_del_url_name), ] extra_urls = self.extra_urls() if extra_urls: urlpatterns.extend(extra_urls) return urlpatterns def extra_urls(self): # 用于扩展url 返回的是一个列表,一次性扩展多个值 pass @property def urls(self): return self.get_urls()
...

这样就完成了注册与路由构建。

猜你喜欢

转载自www.cnblogs.com/shenjianping/p/10902852.html