公用插件开发-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 阅读(146) 评论(0) 编辑 收藏 举报