既然我们要做一个Xadmin组件,那么这个组件要有一定的复用的功能,所以要进行一系列的配置,当我们把这个组件复制到别的项目中,要知道如何使用
还是看一看整个项目的组织结构
app01和02是两个我们一般的app,还有Xadmin也是一个创建的app,但是是Xadmin组件,所以在setting.py里要把这三个app添加进去,这个没什么好说的
下面我们需要的就是仿照admin里的源代码写一个方法
1 from .decorators import register as register 2 from .filters import ( 3 AllValuesFieldListFilter as AllValuesFieldListFilter, 4 BooleanFieldListFilter as BooleanFieldListFilter, 5 ChoicesFieldListFilter as ChoicesFieldListFilter, 6 DateFieldListFilter as DateFieldListFilter, 7 FieldListFilter as FieldListFilter, 8 ListFilter as ListFilter, 9 RelatedFieldListFilter as RelatedFieldListFilter, 10 RelatedOnlyFieldListFilter as RelatedOnlyFieldListFilter, 11 SimpleListFilter as SimpleListFilter, 12 ) 13 from .helpers import ACTION_CHECKBOX_NAME as ACTION_CHECKBOX_NAME 14 from .options import ( 15 HORIZONTAL as HORIZONTAL, 16 VERTICAL as VERTICAL, 17 ModelAdmin as ModelAdmin, 18 StackedInline as StackedInline, 19 TabularInline as TabularInline, 20 ) 21 from .sites import AdminSite as AdminSite, site as site 22 from . import checks as checks 23 24 def autodiscover() -> None: ...
admin里的代码有个功能就是保证了django项目在启动的时候直接运行所有admin.py这个文件。那么我们要让Django启动的时候运行所有的Xadmin文件(这里省略了一个操作:把各个app里的admin文件改名为Xadmin)。
现在主要看一下Xadmin里面的几个py文件,要改的就是app.py
""" Xadmin/app.py """ from django.apps import AppConfig from django.utils.module_loading import autodiscover_modules class XadminConfig(AppConfig): name = 'Xadmin' def ready(self): autodiscover_modules('Xadmin')
上面的这段代码就保证了Django项目运行 到时候执行每个app下名字为Xadmin这个文件。
大概整个流程是这样的:
settings.py里制定了这个app里的类(倒数第三行)
1 INSTALLED_APPS = [ 2 'django.contrib.admin', 3 'django.contrib.auth', 4 'django.contrib.contenttypes', 5 'django.contrib.sessions', 6 'django.contrib.messages', 7 'django.contrib.staticfiles', 8 'Xadmin.apps.XadminConfig', 9 'app01.apps.App01Config', 10 'app02.apps.App02Config' 11 ]
这个类里的ready方法是在这个类一旦被加载后直接执行的方法。
然后要按照admin的方式构造一个类似与admin.site的单例对象,因为我们要做的是一个组件,就把整个Xadmin做成一个组件
1 """ 2 /Xadmin/service/Xadmin.py 3 """ 4 class modelXadmin(object): 5 def __init__(self,model,site): 6 self.model = model 7 self.site = site 8 9 class XadminSite(object): 10 def __init__(self,name = 'admin'): 11 self._registry = {} 12 13 14 def register(self,model,admin_class=None,**options): 15 if not admin_class: 16 admin_class = modelXadmin 17 18 self._registry[model] = admin_class(model,self) 19 20 site = XadminSite() #基于模块的单例对象
然后就可以在各个app里引入这个单例对象了,下面只列出了app01里的注册方法
1 #下面这个admin的组件多久不用了 2 #from django.contrib import admin 3 4 # Register your models here. 5 6 from Xadmin.service.Xadmin import site 7 from . import models 8 #table的注册 9 site.register(models.Books) 10 site.register(models.Publisher)
这样就回到我们前面讲的admin的使用了。
url的封装
前面一张我们了解了URL的设计思路,但是我们需要把这个URL封装到Xadmin这个包中以备后期使用。这个URL的封装还是有点意思的,先看看Django源代码里urls.py里有下面的一行代码
path('admin/', admin.site.urls),
点进去看一看这个site里的urls到底是个什么
@property def urls(self) -> Tuple[List[URLResolver], str, str]: ...
还是通过property装饰器把类里的方法变成了属性,那么在url里直接通过调用直接就运行了(没有装饰器的话必须加括号才能运行)
内置了URL分发的XadminSite类
class XadminSite(object): def __init__(self,name = 'admin'): self._registry = {} def register(self,model,admin_class=None,**options): if not admin_class: admin_class = modelXadmin self._registry[model] = admin_class(model,self) @property def urls(self): return self.get_urls(),None,None def get_urls(self): temp = [] for model,admin_class_obj in self._registry.items(): model_name = model._meta.model_name app_name = model._meta.app_label temp.append(url(r"^{0}/{1}/".format(app_name,model_name),self.urls2),) return temp @property def urls2(self): return self.get_urls_2(),None,None def get_urls_2(self): temp = [] temp.append(url(r'^$',self.list_view)) temp.append(url(r'^add/$',self.add_view)) temp.append(url(r'^(d+)/change/$',self.change_view)) temp.append(url(r'^(d+)/delete/$',self.delete_view)) return temp def list_view(self,request): return HttpResponse('list_view') def add_view(self,request): return HttpResponse('list_view') def change_view(self,request,id): return HttpResponse('list_view') def delete_view(self,request,id): return HttpResponse('list_view')
在这里的视图我们只是通过代码实现了分发的效果。
后面就是要完成模板的设计了。