如何实现注册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