admin 组件
Django 自带的用户后台组件
用于用户便携的操作
admin 组件核心
- 启动
- 注册
- 设计url
启动核心代码
每个app 通过 apps.py 扫描 admin.py 文件 并执行
""" setting.py setting.py 中会对注册的 app 自动加载各自里面的 AppxxConfig 模块 """ INSTALLED_APPS = [ ... 'app01.apps.App01Config', 'app02.apps.App02Config', ]
""" apps.py app下的里面的 adminConfig 在自动执行的时候可以进行启动操作 """ from django.apps import AppConfig class App01Config(AppConfig): name = 'app01'
""" admin 源码 调用每个app 下的admin.py 文件进行执行 """ import admin # 执行每一个app下的admin.py文件 autodiscover_modules('admin', register_to=site)
""" admin.py 被执行的 admin.py 文件 """ from django.contrib import admin from rbac.models import * # Register your models here.
注册核心代码
在admin.py 文件中对表进行注册
注册后的表要判断是否有自定义的配置文件
若没有则使用默认的 Modeladmin
""" admin 注册流程核心源码 """ class AdminSite(object): def __init__(self,name="admin"): # 定义一个空字典用于保存注册 self._registry={} # 注册函数 # 需要有两个参数, 被注册的表 以及 是否有自定义的配置操作 def register(self, model, admin_class=None, **options): # 首先对是否存在自定义配置操作进行判断 if not admin_class: # 如果无自定义则用默认的 admin_class = Modeladmin # 有自己的就用自己的 # 注意这里的键为类名而不是字符串 self._registry[model] = admin_class(model, self) # {Book:ModelAdmin(Book),Publi sh:ModelAdmin(Publish)} # 进行实例化实现单例模式 # 其他所有的程序中的 admin 通过引入,用的都是这个对象 site=AdminSite()
""" admin.py 中对表进行注册操作 """ from django.contrib import admin from rbac.models import * # Register your models here. # 基于模块的单例模式从而实现所有的注册表都使用的同一个 admin.site 对象 admin.site.register(User) admin.site.register(Role) admin.site.register(Permission)
URL 分发核心代码
调用 urls() 方法
然后继续调用 get_urls() 方法
遍历所有注册表,进行URL 的拼接合成最后生成一个列表返回给 urls.py
最终在urls.py 进行调用
""" urls.py urls.py 中全部写成了一条 所有的结果都在调用 urls方法后拿到 """ urlpatterns = [ url(r'^admin/', admin.site.urls), ]
""" admin 设计url 核心 """ class AdminSite(object): def get_urls(self): urlpatterns = [ url(r'^$', wrap(self.index), name='index'), url(r'^login/$', self.login, name='login'), url(r'^logout/$', wrap(self.logout), name='logout'), url(r'^password_change/$', wrap(self.password_change, cacheable=True), name='password_change'), url(r'^password_change/done/$', wrap(self.password_change_done, cacheable=True), name='password_change_done'), url(r'^jsi18n/$', wrap(self.i18n_javascript, cacheable=True), name='jsi18n'), url(r'^r/(?P<content_type_id>d+)/(?P<object_id>.+)/$', wrap(contenttype_views.shortcut), name='view_on_site'), ] valid_app_labels = [] # 遍历注册过的表,对每个表生成 相应的 url 进行链接起来 for model, model_admin in self._registry.items(): urlpatterns += [ url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)), ] if model._meta.app_label not in valid_app_labels: valid_app_labels.append(model._meta.app_label) if valid_app_labels: regex = r'^(?P<app_label>' + '|'.join(valid_app_labels) + ')/$' urlpatterns += [ url(regex, wrap(self.app_index), name='app_list'), ] # 返回给urls 得出的 urls列表 # 所有的urls 保存在 urlpatterns列表里面 return urlpatterns # 调用 get_urls 获得全部的结果 def urls(self): # 给urls.py 返回回去 return self.get_urls(), 'admin', self.name
ps:
url 的设计和分发合成是什么时候完成?
答案:
在项目启动的时候就完成
在表进行注册后,就已经生成了,而不是url来了再生成
本质上 django 启动就已经是启动了文件,不然你的admin 单例从何而来
模拟完成一个 Xadmin 组件实现 admin 组件的功能
""" 自己实现一个 Xadmin 模块来替换掉 admin 和 admin 一样需要 启动 注册 url 分发 """ """ 启动 """ # setting.py INSTALLED_APPS = [ ... 'Xadmin.apps.XadminConfig', 'app01.apps.App01Config', 'app02.apps.App02Config', ] # apps.py from django.apps import AppConfig from django.utils.module_loading import autodiscover_modules # Xadmin.py class XadminConfig(AppConfig): name = 'Xadmin' """ 启动 """ def ready(self): autodiscover_modules('Xadmin') class ModelXadmin(object): def __init__(self,model,site): self.model=model self.site=site """ url 分发 二级分发和视图函数放在 配置类里面 不放在 注册类里面的原因: 因为注册类 单例生成 导致所有的注册表的self里面无法区分出来彼此的 配置类 如果放在 配置类中 self 就是注册表自己对应的 配置类 根本拿不到想要的数据(比如 表 本身) 比如 在 配置类 中 self.model 就是那个表,(在init 中注册的都可以随便拿来用了) """ def list_view(self, request): print("self.model",self.model) data_list=self.model.objects.all() print("data_list",data_list) return render(request, 'list_view.html',{"data_list":data_list}) def add_view(self, request): return render(request, 'add_view.html') def change_view(self, request, id): return render(request, 'change_view.html') def delete_view(self, request, id): return render(request, 'delete_view.html') def get_urls2(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 @property def urls2(self): return self.get_urls2(), None, None class XadminSite(object): def __init__(self,name="admin"): self._registry={} """ 注册 """ def register(self, model, admin_class=None, **options): if not admin_class: admin_class = Modeladmin self._registry[model] = admin_class(model, self) """ url 分发 """ def get_urls(self): temp = [] for model, admin_class_obj in self._registry.items(): app_name = model._meta.app_label model_name = model._meta.model_name temp.append(url(r'^{0}/{1}/'.format(app_name, model_name), admin_class_obj.urls2), ) return temp @property def urls(self): return self.get_urls(),None,None site=XadminSite()
# url.py from Xadmin.service.Xadmin import site urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^Xadmin/', site.urls), ] """ 其他的程序使用方式
和以往admin的方式基本一致 """ """ 启动 """ # setting.py INSTALLED_APPS = [ ... 'app01.apps.App01Config', "app02.apps.App02Config" ] # apps.py from django.apps import AppConfig class App01Config(AppConfig): name = 'app01' # Xadmin.py from Xadmin.service.Xadmin import site, ModelXadmin """ 注册 """ site.register(Book, BookConfig)