Third_django_自定制Admin_图书馆1.0版

sites代码块

from django.urls import path, re_path
from django.shortcuts import HttpResponse, render
from app01 import models
from django.urls import reverse
from django.utils.safestring import mark_safe


class ModelStark(object):
    """
    默认配置类
    """
    list_display = ("__str__",)  # 创建一个变量,如果用户没有自定义则走默认的模型str(str在app01的models定义了),用来满足自定制,
# 注意这里要加逗号,因为下面会迭代追加,一个字符串会分成一个个 # print(list_display,
"list_display") def __init__(self, model): print("init") self.model = model self.model_name = self.model._meta.model_name # 获取model名称 self.app_label = self.model._meta.app_label # 获取model所在app名称 # 反向解析当前访问表的增删改查URL,为什么用反向解析,就是为了拓展性更好 def get_list_url(self): # 反向解析当前表的URL list_url = reverse("%s_%s_list" % (self.app_label, self.model_name)) return list_url def get_add_url(self, obj): # 反向解析当前表的添加URL add_url = reverse("%s_%s_add" % (self.app_label, self.model_name)) return add_url def get_delete_url(self, obj): # 反向解析当前表的删除URL,args 获取当前obj的pk值,下面list_views里面获取了每条对象,即obj delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,)) return delete_url def get_change_url(self, obj): # 反向解析当前表的编辑URL change_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,)) return change_url # 三个默认的列,即功能 def show_checkbox(self, obj=None, header=False): """ mark_safe: 将添加的字节进行编译,HTML默认将添加字节做字符串处理 :param obj: None :param header: True :return: """ if header: return mark_safe("<input type='checkbox'>") return mark_safe("<input type='checkbox'>") def show_delbtn(self, obj=None, header=False): if header: return "删除" return mark_safe("<a href='%s'>删除</a>" % self.get_delete_url(obj)) def show_editbtn(self, obj=None, header=False): """ mark_safe: 将添加的字节进行编译,HTML默认将添加字节做安全处理,这是告诉它此字符串是安全的 :param obj: 每条数据的对象 :param header: 如果添加header命名则走自定制页面 :return: """ if header: return "编辑" return mark_safe("<a href='%s'>编辑</a>" % self.get_change_url(obj)) # 构建新的list_display def get_new_list_display(self): temp = [] temp.extend(self.list_display) # 迭代增加元素,即将list_display拆开一个个添加进去 temp.append(ModelStark.show_delbtn) # 将删除模型类对象添加进去 temp.append(ModelStark.show_editbtn) # 将编辑模型类对象添加进去 temp.insert(0, ModelStark.show_checkbox) # 多选按钮插入到第0个位置 """ [<function ModelStark.show_checkbox at 0x0000025CCDED1C80>, 'title', 'price', 'state', 'publisher', <function BookConfig.show_authors at 0x0000025CCDED1400>, <function ModelStark.show_delbtn at 0x0000025CCDED1D08>, <function ModelStark.show_editbtn at 0x0000025CCDED1D90>] """ return temp # 此时temp如上 def list_view(self, request): queryset = self.model.objects.all() # 获取当前对象的Queryset,即当前book表或publish表数据 # 构建表头,将表头和表内数据分开成两个列表 header_list = [] for field_or_func in self.get_new_list_display(): # print("field_or_func", field_or_func) if callable(field_or_func): # 判断是否可调用对象 val = field_or_func(self, header=True) # 将函数header改成True并调用得到值做表头 header_list.append(val) # 是的话调用函数并将值添加到表头 else: if field_or_func == "__str__": val = self.model._meta.model_name.upper() else: # app01.Book.title 取到对应models模型字段的对象 field_obj = self.model._meta.get_field(field_or_func) # 获取到对应表头名 val = field_obj.verbose_name header_list.append(val) # 构建展示数据 new_data = [] for obj in queryset: # 将当前表数据循环获取出每一条的对象!!! temp = [] for field_or_func in self.get_new_list_display(): # 循环新display列表, 并将内容取出来 if callable(field_or_func): # 如果是可调用对象 val = field_or_func(self, obj) # 运行函数并获取值 else: try: from django.db.models.fields.related import ManyToManyField field_obj = self.model._meta.get_field(field_or_func) # 获取到对象 # 判断是否多对多字段,判断该函数需要导入上面模块,如果直接写多对多则报错,需要自己写函数 if type(field_obj) == ManyToManyField: raise Exception("list_display can't many To many") # 判断字段是否拥有 choices 属性 if field_obj.choices: # obj.get_state_display() 该方法能获取到choices对象目前的值 val = getattr(obj, "get_%s_display" % field_or_func)() else: # 所有对象空间如果有属性值,利用以下方法即可反射获取值 val = getattr(obj, field_or_func) except Exception as e: # 进入publish时,走上面语句则会报错,所以直接用这个方法,近添加首个 val = getattr(obj, field_or_func)() # 直接用str获取当前对象的数据即可 temp.append(val) # 将数据一行一行的添加 new_data.append(temp) print("-------->new_data", new_data) return render(request, 'stark/list_view.html', locals()) def add_view(self, request): # 添加 return HttpResponse("add_view111") def change_view(self, request, id): # 编辑 return HttpResponse("change_view") def delete_view(self, request, id): # 删除 return HttpResponse("delete_view") @property def get_urls(self): # 二级分发路径, 反向解析各种路径 temp = [ path("", self.list_view, name="%s_%s_list" % (self.app_label, self.model_name)), path("add/", self.add_view, name="%s_%s_add" % (self.app_label, self.model_name)), re_path("(\d+)/change/", self.change_view, name="%s_%s_change" % (self.app_label, self.model_name)), re_path("(\d+)/delete/", self.delete_view, name="%s_%s_delete" % (self.app_label, self.model_name)), ] return (temp, None, None) class StarkSite: """ stark 全局类 """ def __init__(self): # 类的单例模式,提高执行效率(都是用同一空间),减少开辟多个内存空间 self._registry = {} def register(self, model, admin_class=None, **options): # model就是用户模型类(指向空间,即book或publish),admin_class 如果用户没有自己创建样式装修则用默认的 admin_class = admin_class or ModelStark # or 的方法,选择为非0的对象赋值 self._registry[model] = admin_class(model) # 给字典不断添加键值对,以model为键,配置类为值 def get_urls(self): # 动态为注册的模型类创建增删改查URL # 创建temp存放path temp = [] # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)} for model, config_obj in self._registry.items(): # 将上面函数拿到的各个模型类键值对提取出来,config_obj就是 model_name = model._meta.model_name # 该方法是拿model的名字(字符串) app_label = model._meta.app_label # 该方法是拿model所在app的字符串 """ 二级分发小例子: urls = [ path('index/', index), path('book/',([ path('test01/', test01), path('test02/', test02), ],None,None)) ] """ # 给temp添加path,即book_manage/book 或 book_manage/publish # config_obj.get_urls 即是增删改查的路径(二级分发),默认就会有自己的二级temp temp.append( path("%s/%s/" % (app_label, model_name), config_obj.get_urls) ) return temp @property def urls(self): # property 方法是使调用它的时候直接使用urls即可调用(默认Admin做的,可以参考urls里面的Admin) return self.get_urls(), None, None # 调用时返回这些值,None是固定传的,一个是app名字一个是空间名字所以直接None site = StarkSite() """ 将全局类实例化成一个对象,所有的调用都使用这个实例化对象, 这样空间就永远是一个,只是实例化键值对来指向它 """

 

posted @ 2019-04-15 21:16  pythonernoob  阅读(99)  评论(0)    收藏  举报