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>

 

此时的前端

 

posted @ 2019-04-12 19:04  pythonernoob  阅读(105)  评论(0)    收藏  举报