公用插件开发-Day2

如何实现注册model?

在app_plug中创建service文件夹,创建v1.py用于接收,封装,和处理model,此处我们首先需要实现的是接收,封装,具体做法如下:

class BasePlugModel:
    def __init__(self, model_class, site):
        self.model_class = model_class
        self.site = site


class AppPlugSite(object):
    def __init__(self):
        self._registry = {}
        self.app_name = "app_plug"
        self.namespace = "app_plug"

    def register(self, model_class, app_plug_model_class=BasePlugModel):
        self._registry[model_class] = app_plug_model_class(model_class, self)

在别的app中注册model时只需要:

v1.site.register(models.UserInfo)

自动生成URL

对于此类问题肯定要首先解决路由分发的问题,以前运用include函数可以将URL分层管理,进入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)

大部分地方可以不用管,我们需要了解的是他的返回值,返回值的属性分别为:url关系列表或模块(模块内部必须有urlpatterns属性);app_name;namespace

了解了返回值之后我们可以自己写一个函数来模仿include函数所做的事,其实这个函数的返回值和include函数的返回值要求相同即可,在AppPlugSite类中创建

    def urls(self):
        """
        创建URL对应关系
        :return: 元组类型:url关系列表或模块(模块内部必须有urlpatterns属性);app_name;namespace
        """
        return self.get_urls(), self.app_name, self.namespace

然后要处理的就是get_urls函数该怎么写,首先要明确的时这个函数的返回值一定是个列表类型,简单的写:

    def get_urls(self):
        """
        封装url至列表
        :return: 装有url的列表
        """
        from django.conf.urls import include
        from django.urls import re_path
        # urlpatterns变量名不能更改,因为include内部实现寻找url时就是查找urlpatterns变量获取
        urlpatterns = [
            # url(r'^$', self.index, name='index'),
            re_path(r'^login/$', self.login, name='login'),
            re_path(r'^logout/$', self.logout, name='logout'),
        ]
        return urlpatterns

然后在urls.py中添加:

re_path(r'^plug/', v1.site.urls),

这样就添加了一些二级的URL,但是我们所要做的是要对任何数据列表进行增删改查的操作,URL格式应该为:http://127.0.0.1:8000/plug/app01/userinfo/1/delete/ 这样的,这个URL所含的信息有包名,models的类名,还有操作方式和操作对象id

获取包名和类名的方法为: 类._meta.app_label,类._meta.model_name,这样在BasePlugModel类中再创建:

    def another_urls(self):
        """
        钩子函数,用于自定义额外的URL
        :return:
        """
        return []

    def get_urls(self):
        """
        配置最后一段URL用于增删改查等操作
        :return:
        """
        from django.urls import re_path
        # 获取包名和类名,方便日后反向生成URL
        info = self.model_class._meta.app_label, self.model_class._meta.model_name
        urlpatterns = [
            re_path(r'^$', self.list_view, name='%s_%s_list' % info),
            re_path(r'^add/$', self.add_view, name='%s_%s_add' % info),
            re_path(r'^(.+)/delete/$', self.delete_view, name='%s_%s_delete' % info),
            re_path(r'^(.+)/change/$', self.change_view, name='%s_%s_change' % info),
            # re_path(r'^(.+)/detail/$', self.detail_view, name='%s_%s_detail' % info),
        ]
        urlpatterns += self.another_urls()
        return urlpatterns

    @property
    def urls(self):
        return self.get_urls()

这样,就可以对任何数据列表进行增删改查的操作。

在AppPlugSite中的完整的get_urls函数为:

    def get_urls(self):
        """
        封装url至列表
        :return: 装有url的列表
        """
        from django.conf.urls import include
        from django.urls import re_path
        # urlpatterns变量名不能更改,因为include内部实现寻找url时就是查找urlpatterns变量获取
        urlpatterns = [
            # url(r'^$', self.index, name='index'),
            re_path(r'^login/$', self.login, name='login'),
            re_path(r'^logout/$', self.logout, name='logout'),
        ]
        # 根据model动态生成URL
        for model_class, plug_model_obj in self._registry.items():
            # 获取包名和类名
            app_label = model_class._meta.app_label
            model_name = model_class._meta.model_name
            # 拼接URL
            urlpatterns += [re_path(r'^%s/%s/' % (app_label, model_name), include(plug_model_obj.urls)), ]
        return urlpatterns

  

posted on 2018-08-02 18:53  yujie158392613  阅读(144)  评论(0编辑  收藏  举报

导航