基于Django-admin实现stark组件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Django-admin实现stark组件相关的知识,希望对你有一定的参考价值。

一、url的分发练习

from django.conf.urls import url
from django.contrib import admin
from django.shortcuts import  HttpResponse
def index(request):
    return HttpResponse("首页")
    
    
def add(request):                         #add视图函数
    return HttpResponse("add")
def list_view(request):                  #list_view视图函数
    return HttpResponse("list_view")
def change(request,id):                  #change视图函数
    return HttpResponse("change")
def delete(request,id):                  #delete视图函数
    return HttpResponse("delete")
    
    
def get_urls2():                        #url的二级分发函数
    temp=[
        url("^add/$",add),
        url("^$",list_view),
        url("^(d+)/change/$",change),
        url("^(d+)/delete/$",delete),
    ]
    return temp
    
def get_urls():
    temp=[]
    for model,model_class_obj in admin.site._registry.items(): # 模型类:该模型类的配置类对象 {Book:ModelAdmin(Book),Publish:ModelAdmn(Publish),....}
          app_name=model._meta.app_label                      #得到应用名
          model_name=model._meta.model_name
          temp.append(url(r"%s/%s/"%(app_name,model_name),(get_urls2(),None,None)))   #url做分发,后面跟元组,元组第一项为一个列表
    return  temp
    
from stark.service.sites import site
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r"^stark",(get_urls(),None,None))
]

二、实现stark组件


app01应用的models.py文件:

from django.db import models
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,verbose_name="编号")
    title = models.CharField( max_length=32,verbose_name="名称")
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格")
    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors=models.ManyToManyField(to='Author',)
    def __str__(self):
        return self.title
        
        
#执行下面python语句生成相关表(数据迁移)
# python3 manage.py makemigrations
# python3 manage.py migrate

项目下的settings.py文件设置:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    "app02.apps.App02Config",
    "stark.apps.StarkConfig",
]


STATIC_URL = '/static/'
STATICFILES_DIRS=[
    os.path.join(BASE_DIR,"static")
]

项目的urls.py文件:

from django.conf.urls import url
from django.contrib import admin
from stark.service.sites import site
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^stark/', site.urls),               #模拟admin的实现方式,在stark目录后面进行分发
]

app01应用的stark.py文件对app01的应用表进行注册:


from stark.service.sites import site,ModelStark
from app01.models import Book
from app01.models import Publish
from app01.models import Author
class BookConfig(ModelStark):
    # def display_authors(self, obj=None,is_header=False):     #显示多对多字段,单独定义函数实现方式
    #
    #     if is_header:
    #         return "作者"
    #     s=[]
    #     for author in obj.authors.all():
    #         s.append(author.name)
    #
    #     return " ".join(s)
    list_display = ["nid","title","price","publish","authors",]
    # list_display = ["nid","title","price","publish",display_authors]
site.register(Book,BookConfig)
site.register(Publish)
site.register(Author)

项目下的stark目录下apps.py定义执行各个应用的stark.py:


from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules
class StarkConfig(AppConfig):
    name = 'stark'
    def ready(self):
        autodiscover_modules('stark')      # 执行每一个app下的stark.py

项目下的stark目录下service目录下sites.py定义对用户访问url的分发:

from django.conf.urls import url
from django.shortcuts import HttpResponse, render
from django.utils.safestring import mark_safe
class ModelStark():                    #将增,删,改,查写到ModelStark类中,这样谁调用类中的功能,self.model就是用户访问的表
    list_display = ["__str__", ]
    def __init__(self, model, site):
        self.model = model
        self.site = site
    def edit(self, obj=None, is_header=False):
        if is_header:
            return "操作"                                                   #表头返回 "操作"
        return mark_safe("<a href='%s/change'>编辑</a>" % obj.pk)        #mark_safe会识别返回的html标签
    def delete(self, obj=None, is_header=False):
        if is_header:
            return "操作"
        return mark_safe("<a href='%s/delete'>删除</a>" % obj.pk)
    def checkbox(self, obj=None, is_header=False):
        if is_header:
            return "选择"
        return mark_safe("<input type='checkbox' pk=%s>" % obj.pk)        #在对应位置显示多选框
    def add(self, request):
        return HttpResponse("add")
    def new_list_display(self):                 #新的显示样式,这样所有表的显示都有多选框,编辑和删除操作
        temp = []
        temp.append(ModelStark.checkbox)
        temp.extend(self.list_display)
        temp.append(ModelStark.edit)
        temp.append(ModelStark.delete)
        return temp
    def list_view(self, request):
        print(self.model)
        data_list = self.model.objects.all()
        print("list_display", self.list_display)  # ["nid","title","price",edit]
        # 处理表头
        header_list = []
        for field in self.new_list_display():
            if isinstance(field, str):                              #判断field是字符串类型
                if field == "__str__":                            #字段是__str__
                    val = self.model._meta.model_name.upper()        #表头显示表名的大写字母
                else:
                    field_obj = self.model._meta.get_field(field)
                    val = field_obj.verbose_name                      #得到字段的verbose_name,定义后可以显示中文
            else:
                val = field(self, is_header=True)                  #field是函数,执行函数
            header_list.append(val)
        # 处理表单数据
        new_data_list = []
        for obj in data_list:
            temp = []
            for field in self.new_list_display():  # ["nid","title","price","authors",edit]    ['__str__']     ["title","price"]
                if isinstance(field, str):
                    try:
                        from django.db.models.fields.related import ManyToManyField
                        field_obj = self.model._meta.get_field(field)          #得到field的字段对象
                        if isinstance(field_obj, ManyToManyField):            #判断是多对多关系的字段
                            l = []
                            for i in getattr(obj, field).all():             #.all()得到所有的对象,否则none
                                l.append(str(i))
                            val = ",".join(l)
                        else:
                            val = getattr(obj, field)
                            print("val", val)
                    except Exception as e:
                        val = getattr(obj, field)                      #反射,取到字段名
                else:
                    val = field(self, obj)
                temp.append(val)
            new_data_list.append(temp)
        return render(request, "list_view.html", locals())
    def change(self, request, id):
        return HttpResponse("change")
    def delete_view(self, request, id):
        return HttpResponse("delete_view")
    def get_urls2(self):
        temp = [
            url("^add/$", self.add),
            url("^$", self.list_view),
            url("^(d+)/change/$", self.change),
            url("^(d+)/delete/$", self.delete_view),
        ]
        return temp
    @property
    def urls2(self):
        return self.get_urls2(), None, None
        
        
class StarkSite():
    def __init__(self, ):
        self._registry = {}
    # 一级分发
    def get_urls(self):
        temp = []
        for model, model_class_obj in self._registry.items():  # {Book:ModelAdmin(Book),Publish:ModelAdmn(Publish),....}
            app_name = model._meta.app_label
            model_name = model._meta.model_name
            temp.append(url(r"%s/%s/" % (app_name, model_name), model_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 = ModelStark
        self._registry[model] = admin_class(model, self)
        
        
site = StarkSite()

list_view.html页面:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bs/css/bootstrap.css">
</head>
<body>
<h3>查看数据</h3>
<div>
    <div>
        <div>
            <table class="table table-bordered table-hover table-striped">
                <thead>
                     <tr>
                          {% for foo in header_list %}
                          <th>{{ foo }}</th>
                          {% endfor %}
                     </tr>
                </thead>
                <tbody>
                      {% for new_data in new_data_list %}
                      <tr>
                         {% for foo in new_data %}
                         <td>{{ foo }}</td>
                         {% endfor %}
                      </tr>
                      {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>
</html>

三、显示多对多字段的另一种方法


stark.py注册表时自定义函数:

class BookConfig(ModelStark):
    def display_authors(self, obj=None,is_header=False):     #显示多对多字段
        if is_header:
            return "作者"
        s=[]
        for author in obj.authors.all():
            s.append(author.name)
        return " ".join(s)
    list_display = ["nid","title","price","publish",display_authors]

sites.py里面的ModelStark类定义的list_view

def list_view(self, request):
    print(self.model)
    data_list = self.model.objects.all()
    print("list_display", self.list_display)  #  ["nid","title","price",edit]
    # 处理表头
    # header_list=["ID","名称","价格"]
    header_list=[]
    for field in self.new_list_display():
        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)
        header_list.append(val)
    # 处理表单数据
    new_data_list = []
    for obj in data_list:
        temp = []
        for field in self.new_list_display():  #   ["nid","title","price","authors",edit]    ['__str__']     ["title","price"]
            if isinstance(field,str):
                val = getattr(obj, field)
            else:
                val=field(self,obj)
            temp.append(val)
        new_data_list.append(temp)

页面显示效果图:

技术分享图片



以上是关于基于Django-admin实现stark组件的主要内容,如果未能解决你的问题,请参考以下文章

django-admin 仿写stark组件action,filter筛选过滤,search查询

使用自己的stark组件实现crm系统

stark 组件 url 二级分发的实现

stark组件

stark组件

stark组件之批量操作模仿Django的admin