• 仿照admin的stark自定义组件的功能实现


    仿照admin的stark自定义组件的功能实现:其中最主要的就是增删改查的实现

    1、查:首先页面中显示表头和数据,都是动态的,而不是写死的。

    (1) 先看表头和表单数据:这个是查看的视图函数,但是为了使视图函数里边的代码简洁,在默认配置类的外部定义一个展示类,

    因为在展示页面上会展示我们数据库中的数据,搜索框,过滤框,等。所以专门定义一个展示类。

    # 查看视图函数,将此里边的函数封装成一个函数
        def listview(self, request):
            # print(self)  # 当前访问模型表的配置类对象
            # print(self.model)  # 当前访问模型表
            # print(self.list_display)
            if request.method == "POST":
                # 获取到我们选中的id,即对象
                pk_list = request.POST.getlist("pk_list")
                # 看id是否在pk_list中
                queryset = self.model.objects.filter(pk__in=pk_list)
                # 或取到这个名字即函数名
                action = request.POST.get("action")
                # 因为获取的是字符串,所以要用反射,self表示配置类对象
                # 判断是否存在
                if action:
                    action=getattr(self,action)
                    action(request,queryset)
            data_list = self.model.objects.all()
            # 在这个页面上增加一个增加数据的按钮,跳转到那个路径
            add_url = self.get_add_url()
            # 获取搜索条件对象
            search_condition = self.get_search_condition(request)
            # 获取filter的condition
            filter_condition = self.get_filter_condition(request)
    
            # 数据过滤展示
            data_list = data_list.filter(search_condition).filter(filter_condition)
            # 分页展示
            showlist = ShowList(self, data_list, request)
            # filter,调用
            showlist.get_list_filter()
    
            return render(request, "list_view.html", locals())

    展示类:

    class ShowList(object):
        # 初始化
        def __init__(self, config_obj, data_list, request):
            self.config_obj = config_obj  # 当前查看表的配置类对象
            self.data_list = data_list
            self.request = request
    
            # 分页
            self.pagination = MyPage(request.GET.get("page", 1),self.data_list.count(),request,per_page_data=3)
            self.page_queryset = self.data_list[self.pagination.start:self.pagination.end]
    
        # actions操作
        def get_new_actions(self):
            temp = []
            temp.extend(self.config_obj.actions)
            temp.append(self.config_obj.patch_delete)
            new_actions = []
            print(self.config_obj.actions)   # [patch_init,patch_delete]这个对象
            print(temp)
            for func in temp:
                new_actions.append({
                    "text":func.desc,
                    "name":func.__name__
                })
            # print(new_actions)
            # [{'text': '价格初始化', 'name': 'patch_init'}, {'text': '批量删除', 'name': 'patch_delete'},
            return new_actions
    
        # 表头函数
        def get_headers(self):
            # 构建表头
            # 想要的形式是这种形式header_list=["书籍名称","价格"]
            header_list = []
            for field_or_func in self.config_obj.new_list_display():  # 依然循环["title","price","publish",edit]
                # 如果是函数的话这样
                if callable(field_or_func):
                    # 如果是函数
                    val = field_or_func(self.config_obj, is_header=True)
                else:
                    # # 如果只是单纯的字符串字段
                    # 如果这个字段是__str__
                    if field_or_func == "__str__":
                        val = self.config_obj.model._meta.model_name.upper()
                        print(val)
                    else:
                        # 获取到的是字段里边的verbose_name,如果没这个就是默认的表明
                        field_obj = self.config_obj.model._meta.get_field(field_or_func)
                        val = field_obj.verbose_name
                header_list.append(val)
            return header_list
    
        # 表单数据部分
        def get_body(self):
            # 构建数据表单部分
            new_data_list = []  # 先创建一个外层列表,在这个列表里边放小列表
            for obj in self.page_queryset:  # 循环 这个对应的列表,Queryset[book1,book2]
                temp = []  # 小列表
                for field_or_func in self.config_obj.new_list_display():
                    # 循环的就是你display中的东西,不仅有字段相对应的字符串,还可能有自定义的函数["title","price","publish",edit]
                    # 故要做判断,callable是判断是否是函数,
                    if callable(field_or_func):
                        # 如果是函数,则执行这个函数
                        val = field_or_func(self.config_obj, obj)
                    else:
                        # 如果是字符串,
                        # 如果是多对多字段,先导入一个from django.db.models.fields.related import ManyToManyField
                        # 这个是获取出来字段,
                        try:
                            field_obj = self.config_obj.model._meta.get_field(field_or_func)
                            print(field_obj)
                            # app01.Book.title
                            # app01.Book.price
                            # app01.Book.publish
                            # app01.Book.authors
                            if isinstance(field_obj, ManyToManyField):
                                # 然后判断哪个字段是多对多字段,isinstance就是判断是否是多对多字段
                                # 如果是就要用.all()全部获取出来,
                                rel_data_list = getattr(obj, field_or_func).all()
                                print(rel_data_list)
                                # 获取出来每本书对应的作者这个对象
                                # <QuerySet [<Author: 沈巍>, <Author: 蓝忘机>]>
                                l = [str(item) for item in rel_data_list]
                                # 经过for循环,并且转成字符串,用|隔开
                                val = "|".join(l)
                                # 如果这个字段在links里边,获取一下路径,生成a标签
                                if field_or_func in self.config_obj.list_display_links:
                                    _url = self.config_obj.get_change_url(obj)
                                    val = mark_safe("<a href='%s'>%s</a>"%(_url, val))
                            else:
                                # 如果不是多对多字段,就直接获取就行
                                val = getattr(obj, field_or_func)  # 反射
                                # 如果这个字段在links里边,获取一下路径,生成a标签
                                if field_or_func in self.config_obj.list_display_links:
                                    _url = self.config_obj.get_change_url(obj)
                                    val = mark_safe("<a href='%s'>%s</a>"%(_url, val))
                        except Exception as e:
                            val = getattr(obj, field_or_func)  # 反射
                    # 都添加到小列表中
                    temp.append(val)
                # 添加到大列表中
                new_data_list.append(temp)
            return new_data_list
    
        # filter操作,可以写在listview里边,但是为了listview里边代码清晰,所以写在这个类里边
        def get_list_filter(self):
            # 这个弄成字典,是为了前端方便获取,而且方便存值
            list_filter_links = {}
            # for 循环这个字段列表 ['publish', 'authors']
            for field in self.config_obj.list_filter:
                # 因为这个要保存之前的路径
                parmas = copy.deepcopy(self.request.GET)
                # 获取当前字段的id
                current_pk = parmas.get(field, 0)
                # 获取这个字段的对象
                field_obj = self.config_obj.model._meta.get_field(field)
                # 固定语法,得到关联字段的那张表
                rel_model = field_obj.rel.to
                # 得到这个表之后,直接获取这个表的所有数据
                rel_model_queryset = rel_model.objects.all()
                # < QuerySet[ < Publish: 镇魂出版社 >, < Publish: 忘羡出版社 >, < Publish: 北京出版社 >, < Publish: 晋江出版社 >] >
                # print(rel_model_queryset)
                # 得到这个出版社后,在for循环
                temp = []
                for obj in rel_model_queryset:
                    # 字典,键是字段,值是id值
                    parmas[field] = obj.pk
                    if obj.pk == int(current_pk):
                        # 如果字典中的id值和当前获取的一致,颜色变色
                        link = "<a class='active' href='?%s'>%s</a>" % (parmas.urlencode(), str(obj))
                    else:
                        # 其他颜色不变化,
                        link = "<a href='?%s'>%s</a>" % (parmas.urlencode(), str(obj))
                    temp.append(link)
                list_filter_links[field] = temp
            return list_filter_links

    如果是自定义列的话,应该将list_display做一下调整

    # 定义一个新的列表,既存放字段,有存放edit,delete,checkbox
        def new_list_display(self):
            temp = []
            # 把我原来的list_display数据添加进去
            temp.extend(self.list_display)
            # 把checkbox插入在第一位
            temp.insert(0, ModelStark.checkbox)
            # 继续往后添加edit字符串
            # 我们因为增加了一个link属性,所以就在这里判断一下,
            # 如果有links这个属性,我们就不添加增加这个属性了,如果没有的话,我们增加
            if not self.list_display_links:
                temp.append(ModelStark.edit)
            # 继续往后添加删除字符串
            temp.append(ModelStark.delete)
            return temp
    # 默认操作函数
        def edit(self, obj=None, is_header=False):
            if is_header:
                return "操作"
            return mark_safe("<a href='%s' class='btn btn-warning btn-sm'>编辑</a>" % self.get_change_url(obj))
    
        def delete(self, obj=None, is_header=False):
            if is_header:
                return "删除"
            return mark_safe("<a href='%s' class='btn btn-danger btn-sm'>删除</a>" % self.get_delete_url(obj))
    
        def checkbox(self, obj=None, is_header=False):
            if is_header:
                return "选择"
            return mark_safe("<input type='checkbox' name='pk_list' value=%s>" % obj.pk)

    (2)表单表头部分应该注意的有:

    1)在表单数据显示部分有多对多字段的,原生admin是没有做操作的,因为原生的没有规定以什么分割,但是在这里我们进行了操作,是以|分割的,所以可以显示。

    2)自定义列的时候,首先判断是普通字段,还是我们自定义的函数,如果是普通字段,因为得到的是字符串,所以用反射就可以实现

  • 相关阅读:
    php连接mysql数据库
    关于chrome控制台警告:Synchronous XMLHttpRequest on the main thread
    mac“打不开身份不明的开发者”
    微信小程序开发warning: Now you can provide attr "wx:key" for a "wx:for" to improve performance
    将任何GitHub内的代码转为外部CDN网址
    把自己的代码发布到npm(npm publish)
    wordpress写文章添加gif图片变成静态图片的解决办法
    canvas实现刮刮乐
    api文档管理系统合集
    niubi-job:一个分布式的任务调度框架设计原理以及实现
  • 原文地址:https://www.cnblogs.com/hnlmy/p/9583745.html
Copyright © 2020-2023  润新知