Xadmin
一 启动
1.创建一个Xadmin的app
2.在每个APP中创建Xadmin.py文件
3.在Xadmin中找到apps.py,如下图:
下面的框中内容代表,加载项目时,自动运行整个项目中所有Xadmin.py
二 注册
1.把Xadmin当做组件可以拿到别的应用去用,所以把源码写到Xadmin的app中
在Xadmin中创建一个service包,包中创建一个Xadmin.py
class ModelXadmin(): def __init__(self,model,site): self.model = model self.site = site class XadminSite(object): def __init__(self, name='admin'): self._registry = {} def register(self, model, admin_class=None, **options): if not admin_class: #如果注册时不用自定义样式类,默认用ModelXadmin admin_class = ModelXadmin self._registry[model] = admin_class(model, self)#用自己定制的样式类 site=XadminSite() #实例化一个单例对象site #每次注册都不会重新加载,都会存入_registry的字典中
可以在其他APP中的Xadmin中引入单例对象 进行注册:
from Xadmin.service.Xadmin import site,ModelXadmin from app01.models import * #引用app01下的 数据表 site.register(表名) site.register(Book) site.register(Auth)
三 url分发
把所有构建url分发的函数 封装在ModelXadmin类中,在urls.py中就可以用url(r'^Xadmin/', site.urls)
from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect class ModelXadmin(object): def __init__(self,model,site): self.model=model self.site=site 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 get_urls(self): print(self._registry) # {Book:modelAdmin(Book),.......} 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 def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelXadmin self._registry[model] = admin_class(model, self) # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)} site=XadminSite()
四
如何在不同url的相同视图函数中,展示不同的数据
1 先创建增删改查的html文件,在视图中renderhtml页面
2 注册的时候如果不传自己的样式,所有模型表都默认 用的admim_class样式类
把二级分发以及对应的增删改查视图函数,从XadminSite中拿到ModelXadmin(配置类)类中
for model , admin_class_obj in self._registry.items() 中 admin_class_obj 就是ModelXadmin的实例对象,
在XadminSite中拿二级分发就可以 admin_class_obj.urls2,这样就多了一个self.model
访问哪张表,self.model就是哪张表模型,就能拿到对应表的数据,实现相同的模板,渲染不同数据
在视图函数中拿到当前表数据(如图):
五 增删改查的 页面设计
额外知识点:
在后端把标签传给前端,前端会做转义,变成字符串的形式,无法渲染页面,需要用:
from django.utils.safestring import mark_safe mark_safe("<a href=''>编辑</a>")
由于不知道要渲染的数据是谁,所以不能 向之前一样,在模板里渲染
1 需要把数据做成列表套列表的形式:[["title",price],["python红宝书",23],["python宝典",38]]
需要在后端循环当前访问的表(self.model.objects.all())
先在app下的Xadmin中注册的时候,把想展示的字段数据放在list_display 中:list_display=["nid","title","publish"],然后在ModelXadmin中创建一个list_display=[]
如果注册的时候,没有自定义样式类,list_display会为空,所以想要默认显示,需要在ModelXadmin中让list_display=[__str__]
def list_view(self, request)中的代码(要展示的数据):
data_list = self.model.objects.all() #当前访问的页面所有数据 new_data_list=[] for obj in data_list: # data_list [book_obj,book_obj2,...] temp=[] for field in self.list_display: # ['title', 'prcie'] 注册时列表中添加所要展示的字段,如果想在列表添加函数,需要注册时,自定义样式类时,在类中写函数 if isinstance(field,str): #list_display中可能存放函数,所以需要先判断一下 val=getattr(obj,field) #拿到的field是字符串,所以需要用getattr代替obj.field(对象.属性) else: val=field(self,obj) #拿到的是函数(函数中可以返回a标签,编辑,删除),拿到返回值 temp.append(val) #把函数的返回值或者标的字段添加到temp中 new_data_list.append(temp) #把temp列表 放在 new_data_list列表中,做成列表套列表的形式
def list_view(self, request)中的代码(要展示的表头):
返回的一个列表就可以了,虽然list_display存的是每一个字段名,可以循环出来作为表头,但是这样无法修改成中文字段,所以,在创建表字段加一个verbose_name属性:
class Book(models.Model): nid = models.AutoField(primary_key=True,verbose_name=" 编号") title = models.CharField( max_length=32,verbose_name="书籍名称") publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2)
如何显示中文:
创建表 中的每一个字段,其实都是一个实例对象,拿到当前字段的实例对象用:
obj= 表名._meta.get_filed(字段)
然后: obj.verbose_name 就可以拿到中文名
# 处理表头 #header_list=["ID","书籍名称","出版社"] header_list=[] for field in self.list_display: # [check,"nid","title","publish",edit,delete] if isinstance(field,str): if field=="__str__": #如果是字符串,证明没有自定义样式类 val= self.model._meta.model_name.upper() #当前表名大写作为字段 else: field_obj=self.model._meta.get_field(field) val=field_obj.verbose_name else: val=field(self,is_header=True) # 获取表头,传is_header=True 证明拿到的是表头,不需要写修改 删除 header_list.append(val)
当前查看表:
编辑和删除都是空的,那么,如何点击编辑删除,跳转到当前数据的指定页面:
1 在视图中,执行列表中的函数时,把obj,传进去:
else: val=field(self,obj) #拿到的是函数(函数中可以返回a标签,编辑,删除),拿到返回值
2 自定义样式类就可以拿到当前对象,拼接url:
class BookConfig(ModelXadmin): def edit(self,obj=None,is_header=False): #obj=None 调用时,可传可不传。is_header=False,如果传了,证明是表头,不传走下面,返回编辑的a标签 if is_header: return "操作" # 反向解析:url return mark_safe("<a href='%s/change/'>编辑</a>"%obj.pk)
上面这种方式就可以拼接成想要的url,该方法不好,下面用反向解析找到url:
定义视图函数的每一个url路径的时候,起一个name别名