second_Stark(自定制Admin)
全方位解析自定制Admin
1.启动



记得app02也要在settings里面配置,此时可以在两个app里面的stark加print测试是否启动项目即执行,此时的启动步骤已完成
2.注册

class ModelStark(object): """ 默认配置类 """ def __init__(self, model): self.model = model class StarkSite: """ stark 全局类 """ def __init__(self, name='Stark'): # 单例模式,提高执行效率(都是用同一空间),减少开辟多个内存空间 self._registry = {} def register(self, model, admin_class=None, **options): # model就是用户模型类(指向空间),admin_class 如果用户没有自己创建样式装修则用默认的 admin_class = admin_class or ModelStark # or 的方法,选择为非0的对象赋值 self._registry[model] = admin_class(model) # 给字典不断添加键值对,以model为键,配置类为值 site = StarkSite()

from django.db import models # Create your models here. class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() def __str__(self): return self.name class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) # pub_Date = models.DateField() # 如果不设置default,迁移数据就会报错,因为前面的数据程序不知道是1还是2 state = models.IntegerField(choices=[(1, "已出版"), (2, "未出版")], default=1) publisher = models.ForeignKey(to="Publish", on_delete=models.CASCADE, null=True) authors = models.ManyToManyField(to='Author') def __str__(self): return self.title

此时注册也完成
3.设计URL(重点)



from django.urls import path from django.shortcuts import HttpResponse,render class ModelStark(object): """ 默认配置类 """ list_display=("__str__") # 创建一个变量,如果用户没有自定义则走默认的模型str(str在app01的models定义了),用来满足自定制 def __init__(self, model): self.model = model def list_view(self, request): print(self, "who") # 当前访问模型表对应的配置类对象 print(self.model, "who's model") # 当前访问模型表 data = self.model.objects.all() print(data, "data") # 打印值 print(self.list_display, "Do display") # 连接到对应的html,locals(),传给前端 print(locals(), "locals") return render(request, 'stark/list_view.html', locals()) def add_view(self, request): # 添加 return HttpResponse("add_view") 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), path("add/", self.add_view), path("(\d+)/change/", self.change_view), path("(\d+)/delete/", self.delete_view), ] return (temp, None, None) class StarkSite: """ stark 全局类 """ def __init__(self): # 类的单例模式,提高执行效率(都是用同一空间),减少开辟多个内存空间 self._registry = {} def register(self, model, admin_class=None, **options): # model就是用户模型类(指向空间),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就是 print("---->", model, 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() """ 将全局类实例化成一个对象,所有的调用都使用这个实例化对象, 这样空间就永远是一个,只是实例化键值对来指向它 """

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <!-- 可选的 Bootstrap 主题文件(一般不用引入) --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> </head> <body> <h1>查看数据</h1> <table> <tbody> {% for obj in data %} <tr> <td>{{ obj.title }}</td> {# <td>{{ obj.price }}</td>#} </tr> {% endfor %} </tbody> </table> </body> </html>

from stark.servise.sites import site, ModelStark from .models import * class BookConfig(ModelStark): # 自定制的模板,继承ModelStark,也就是还有没有覆盖的ModelStark变量及方法 list_display = ["title", "price"] site.register(Book, BookConfig) site.register(Publish) # print(site._registry)
然后即可启动Django范围,页面如下

注意,此时是写死的显示内容(访问publish就会报错),必须动态,所以需要用到list_display
4.增删改查
再stark.servise.sites添加以下代码进行动态显示数据
from django.urls import path,re_path from django.shortcuts import HttpResponse, render from app01 import models class ModelStark(object): """ 默认配置类 """ list_display=("__str__") # 创建一个变量,如果用户没有自定义则走默认的模型str(str在app01的models定义了),用来满足自定制 # print(list_display, "list_display") def __init__(self, model): self.model = model def list_view(self, request): # print(self, "who") # 当前访问模型表对应的配置类对象 # print(self.model, "who's model") # 当前访问模型表 list_data = list(self.model.objects.all()) # 获取所有的Queryset dic_data = {} for i in range(len(list_data)): dic_data[list_data[i]] = self.model.objects.all()[i].__dict__ need_data = {} # 创建一个空字典用来存放需要显示到前端的值 if self.list_display == "__str__": # 如果自定制配置,就用这个 for k, v in dic_data.items(): a_data = {} for key, val in v.items(): if key != "_state": a_data[key] = val need_data[k] = a_data else: # 以下是非反射方法 for num in range(len(dic_data)): a_data = {} # 生成一个列表,添加完一轮后即刷新,每一个新列表对应一个Queryset数据 for val in self.list_display: a_data[val] = (dic_data[list(dic_data)[num]][val]) # 以键值对形式添加 need_data[num] = a_data # 将存放一条完整的Queryset的值赋予键 # 以下是反射方法 # for i in self.model.objects.all(): # a_data = {} # for val in self.list_display: # if hasattr(i, val): # 判断是否有该方法,无则跳过 # a = getattr(i, val) # a_data[val] = a # 以键值对形式添加 # print(a_data) # need_data[i] = a_data # 执行完如果没有数据(即已经出错了),也会放回一个空列表,后台也不会崩溃 print(need_data, type(need_data)) # 连接到对应的html,locals()传递当前的局部变量 print(locals(), "locals") 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), path("add/", self.add_view), re_path("(\d+)/change/", self.change_view), re_path("(\d+)/delete/", self.delete_view), ] return (temp, None, None) class StarkSite: """ stark 全局类 """ def __init__(self): # 类的单例模式,提高执行效率(都是用同一空间),减少开辟多个内存空间 self._registry = {} def register(self, model, admin_class=None, **options): # model就是用户模型类(指向空间),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就是 print("---->", model, 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() """ 将全局类实例化成一个对象,所有的调用都使用这个实例化对象, 这样空间就永远是一个,只是实例化键值对来指向它 """
在HTML里面写
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <h1>查看数据</h1> <h1>{{ need_data }}</h1> {# <h1>{{ need_data.title }}</h1>#} <table> <tbody> <tr> {% for k,v in need_data.items %} {% if forloop.last %} {% for key,val in v.items %} <th>{{ key }}<span>----------</span></th> {% endfor %} {% endif %} {% endfor %} </tr> {% for k,v in need_data.items %} <tr> {% for key,val in v.items %} <td>{{ val }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </body> </html>
此时的前端




浙公网安备 33010602011771号