Xadmin控件的实现:〇一框架结构
下面这一章节,我们主要来看看整个app的架构和参数
首先,通过文件的目录结构来看一下整个app的组成
配 置
首先,我们需要对app.py文件进行设置,
1 """ 2 /Xadmin/app.py 3 """ 4 from django.apps import AppConfig 5 from django.utils.module_loading import autodiscover_modules 6 7 class XadminConfig(AppConfig): 8 name = 'Xadmin' 9 10 def ready(self): 11 autodiscover_modules('Xadmin')
上面的这段代码,XadminConfig这个类是我们在创建app的时候自动生成的,这个类在setting.py里app注册的时候会用到
1 """ 2 settings.py里APP部分代码 3 """ 4 5 INSTALLED_APPS = [ 6 'django.contrib.admin', 7 'django.contrib.auth', 8 'django.contrib.contenttypes', 9 'django.contrib.sessions', 10 'django.contrib.messages', 11 'django.contrib.staticfiles', 12 'Xadmin.apps.XadminConfig', #在这里引入了这个类 13 'app01.apps.App01Config' 14 ]
但是ready方法是后来写的,目的是让Django项目在一启动的时候去整个项目路径下自动运行名字为Xadmin.py的这个文(在admin组件中是直接运行的admin.py文件,所以在每个新建的app下都默认有一个admin.py文件)。
这一章节主要讲Xadmin组件的框架结构,其余app里的文件先不说了。
Xadmin.py文件
Xadmin文件是整个组件的核心,但其实整个文件结构也就是两个类
1 """ 2 Xadmin.py 3 /Xadmin/service/Xadmin.py 4 """ 5 6 class ConfXadmin(object): 7 pass 8 9 class XadminSite(object): 10 pass 11 12 site = XadminSite()
最后实例化了一个对象,然后通过在别的文件中导入这个对象,是个单实例对象的用法。下面就看看这两个类是怎么写的
上面讲了Xadmin里有两个类,一个是要实例化的对象类,另一个是配置类。先放出来代码,再一步步分析
XadminSite
先把这部分的代码放出来
1 class XadminSite(object): 2 def __init__(self,name = 'Xadmin'): 3 self._registry = {} 4 5 6 def register(self,model,admin_class=None,**options): 7 if not admin_class: 8 admin_class = ConfXadmin 9 10 self._registry[model] = admin_class(model,self) #把各个配置类实例化后的对象作为value放在字典里 11 12 @property 13 def urls(self): 14 return self.get_urls(),None,None 15 16 def get_urls(self): 17 temp = [] 18 19 #这里的admin_class_obj是个很有意思的用法 20 for model,admin_class_obj in self._registry.items(): 21 model_name = model._meta.model_name 22 app_name = model._meta.app_label 23 temp.append(url(r"^{0}/{1}/".format(app_name,model_name),admin_class_obj.urls2),) 24 return temp 25 26 """ 27 上面在循环中获取了admin_class_obj是那个配置类的对象,把url2放在那个类里就能保证在二级分发的时候 28 能拿到当前注册的model 29 """
整个结构很清晰,整体都是从admin的源代码里套路来的。
第6行的register是在对数据库的model进行注册时候的方法,初始化的时候定义了一个空的字典self._registry。然后在注册的时候调用了这个方法,字典的key就是被注册的ORM的类,value就是后面要说的配置类。
注册的时候配置类可以为空,空时就用默认的类,否则就用传进来的类。
第10行里就是把配置类实例化,然后把实例化的对象放到字典里。
第12行里的urls是一个用装饰器修饰的类属性,可以直接调用而不用加括号,所以在urls.py中我们可以直接定义路由
""" urls.py """ from Xadmin.service.Xadmin import site urlpatterns = [ path('admin/', admin.site.urls), url('Xadmin/',site.urls), ]
路由的映射是靠后面的get_urls()来完成的。
get_urls是进行了一级的路由分发,通过一个for循环拿到字典里的每组key-value,然后拿key去拼接出路由的第二、三级。
要注意的一点是这里我们并没有直接写好路由和视图的对应的映射关系。因为每个ORM对应的路由映射的视图是不一样的,必须放在配置类里,那么在初始化的时候每个类都会生成4个视图,所以后面调用了value里的admin_class_obj,也就是ConfXadmin里定义的路由
这里吧ConfXadmin的内容独立放出来,是因为这个是最最重要的一部分
路由映射
在XadminSite里的一级路由分发,是完成了Xadmin/appname/model/这一级的内容,后面的每个model对应的视图都是要在后面这个配置里里生成的
1 class ConfXadmin(object): 2 def __init__(self,model,site): 3 self.model = model 4 self.model_name = self.model._meta.model_name 5 self.app_name = self.model._meta.app_label 6 @property 7 def urls2(self): 8 return self.get_urls2(),None,None 9 10 def get_urls2(self): 11 temp = [] 12 #通过name设置反向解析 13 temp.append(url(r'^$',self.list_view,name='{}_{}_list'.format(self.app_name,self.model_name))) 14 temp.append(url(r'^add/$',self.add_view,name='{}_{}_add'.format(self.app_name,self.model_name))) 15 temp.append(url(r'^(\d+)/change/$',self.change_view,name='{}_{}_change'.format(self.app_name,self.model_name))) 16 temp.append(url(r'^(\d+)/delete/$',self.delete_view,name='{}_{}_delete'.format(self.app_name,self.model_name))) 17 return temp 18 19 def list_view(self,request): 20 return render(request,'list.html') 21 22 def add_view(self,request): 23 return render(request,'add.html') 24 25 def change_view(self,request,id): 26 return render(request,'change.html') 27 28 def delete_view(self,request): 29 return HttpResponse('删除')
我们在site里调用了配置类里的urls2,然后又调用了第10行的映射关系函数。也就是说每个类都对应了这四个增删改查的视图。模板文件非常简单,只放了个最简单的h1标签,就放一个list.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>list视图模板</h1> </body> </html>
运行一下,可以看看效果
注意:要实现上面的效果是要先进行model的注册的
原本想到后面合适的机会把注册这块讲一下,但是因为前面已经用到了,这里就说一下吧
因为我们在本章一开始的时候说过了,在app.py里定义了个ready方法,去运行每个app下的Xadmin.py文件,
新建一个app叫CRUD,然后新建一个Xadmin.py,然后在models.py里迁移数据库.
数据库模型
ORM比较简单,直接用了以前的类
1 # Create your models here. 2 from django.db import models 3 4 class Publisher(models.Model): 5 id = models.AutoField(primary_key=True) 6 name = models.CharField(null = False,max_length=16,verbose_name='名称') 7 8 def __str__(self): 9 return self.name 10 11 class Books(models.Model): 12 id = models.AutoField(primary_key=True) 13 title = models.CharField(null=False,max_length=32) 14 price = models.IntegerField(verbose_name='单价', null=False) 15 publisher = models.ForeignKey(to='Publisher',on_delete=models.CASCADE) 16 publish_time = models.DateField() 17 authors = models.ManyToManyField(to='Author') 18 def __str__(self): 19 return self.title 20 21 class Author(models.Model): 22 id = models.AutoField(primary_key=True) 23 name = models.CharField(null=False,max_length=10,unique=True,verbose_name='姓名') 24 25 def __str__(self): 26 return self.name
然后直接migrate迁移
ORM注册
在新建的Xadmin.py里导入XadminSite里的实例化对象,然后注册
""" /CRUD/Xadmin.py """ from Xadmin.service.Xadmin import site from . import models site.register(models.Books) site.register(models.Publisher)
注册的方法和admin里的方法差不多。