• stark——分页、search、actions


    一、分页

    1、引入自定义分页组件

      在/stark目录下创建utils工具包目录,复制page.py到该目录下,文件中有之前自定义的分页组件。

    class Pagination(object):
        def __init__(self, current_page, all_count, base_url, params, per_page_num=8, pager_count=11, ):
            """
            封装分页相关数据
            :param current_page: 当前页
            :param all_count:    数据库中的数据总条数
            :param per_page_num: 每页显示的数据条数
            :param base_url: 分页中显示的URL前缀
            :param pager_count:  最多显示的页码个数
            """
    
            try:
                current_page = int(current_page)
            except Exception as e:
                current_page = 1
    
            if current_page < 1:
                current_page = 1
    
            self.current_page = current_page
    
            self.all_count = all_count
            self.per_page_num = per_page_num
    
            self.base_url = base_url
    
            # 总页码
            all_pager, tmp = divmod(all_count, per_page_num)
            if tmp:
                all_pager += 1
            self.all_pager = all_pager
    
            self.pager_count = pager_count  # 最多显示页码数
            self.pager_count_half = int((pager_count - 1) / 2)
    
            import copy
            params = copy.deepcopy(params)
            params._mutable = True
            self.params = params  # self.params : {"page":77,"title":"python","nid":1}
    
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page_num
    
    
        @property
        def end(self):
            return self.current_page * self.per_page_num
    
    
        def page_html(self):
            # 如果总页码 < 11个:
            if self.all_pager <= self.pager_count:
                pager_start = 1
                pager_end = self.all_pager + 1
            # 总页码  > 11
            else:
                # 当前页如果<=页面上最多显示(11-1)/2个页码
                if self.current_page <= self.pager_count_half:
                    pager_start = 1
                    pager_end = self.pager_count + 1
    
                # 当前页大于5
                else:
                    # 页码翻到最后
                    if (self.current_page + self.pager_count_half) > self.all_pager:
                        pager_start = self.all_pager - self.pager_count + 1
                        pager_end = self.all_pager + 1
    
                    else:
                        pager_start = self.current_page - self.pager_count_half
                        pager_end = self.current_page + self.pager_count_half + 1
    
            page_html_list = []
            self.params["page"] = 1
            first_page = '<li><a href="%s?%s">首页</a></li>' % (self.base_url, self.params.urlencode(),)
            page_html_list.append(first_page)
    
            if self.current_page <= 1:
                prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
            else:
                self.params["page"] = self.current_page - 1
                prev_page = '<li><a href="%s?%s">上一页</a></li>' % (self.base_url, self.params.urlencode(),)
    
            page_html_list.append(prev_page)
    
            for i in range(pager_start, pager_end):
                #  self.params  : {"page":77,"title":"python","nid":1}
    
                self.params["page"] = i  # {"page":72,"title":"python","nid":1}
                if i == self.current_page:
                    temp = '<li class="active"><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,)
                else:
                    temp = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,)
                page_html_list.append(temp)
    
            if self.current_page >= self.all_pager:
                next_page = '<li class="disabled"><a href="#">下一页</a></li>'
            else:
                self.params["page"] = self.current_page + 1
                next_page = '<li><a href="%s?%s">下一页</a></li>' % (self.base_url, self.params.urlencode(),)
            page_html_list.append(next_page)
    
            self.params["page"] = self.all_pager
            last_page = '<li><a href="%s?%s">尾页</a></li>' % (self.base_url, self.params.urlencode(),)
            page_html_list.append(last_page)
    
            return ''.join(page_html_list)
    /stark/utils/page.py

    2、整合展示数据showlist类实现代码解耦

      将list_view函数中的构建表头代码挪移到ShowList类的get_header函数下,将将list_view函数中的构建表单代码挪移到ShowList类的get_body函数下。

    /stark/serivce/stark.py:

    class ShowList(object):
        """展示页面类"""
        def __init__(self, config, data_list):
            self.config = config   # 接收传递过来的配置类对象
            self.data_list = data_list   # 接收传递过来的当前表的所有对象
    
        def get_header(self):
            """构建表头"""
            header_list = []
            print("header", self.config.new_list_display())  # [checkbox ,"__str__", edit ,deletes]
    
            for field in self.config.new_list_display():
    
                if callable(field):
                    # 如果是函数
                    val = field(self, header=True)
                    header_list.append(val)
    
                else:
                    # 如果是字符串
                    if field == "__str__":
                        header_list.append(self.config.model._meta.model_name.upper())  # 当前模型表名
                    else:
                        # 如果不是"__str__"
                        # header_list.append(field)
                        val = self.config.model._meta.get_field(field).verbose_name
                        header_list.append(val)
    return header_list def get_body(self): """构建表单数据""" new_data_list = [] for obj in self.data_list: temp = [] for field in self.config.new_list_display(): # ["__str__", ] ["pk","name","age",edit] if callable(field): val = field(self.config, obj) else: val = getattr(obj, field) if field in self.config.list_display_links: # _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) _url = self.config.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) temp.append(val) new_data_list.append(temp)
    return new_data_list class ModelStark(object): """代码省略""" def list_view(self, request): data_list = self.model.objects.all() # 拿到对应表所有的对象 show_list = ShowList(self, data_list) # 传入self,即将当前ModelStark的实例对象传给ShowList
    header_list = show_list.get_header()
    new_data_list = show_list.get_body() # 构建一个查看url add_url = self.get_add_url() return render(request, "list_view.html", locals())

    (1)在list_view函数下执行ShowList实例化,在实例化时传入:

      self:即当前ModelStark的实例对象;data_list:对应表所有的对象。

    (2)在新的类ShowList通过__init__方法来接收者两个参数:

    class ShowList(object):
        """展示页面类"""
        def __init__(self, config, data_list):
            self.config = config   # 接收传递过来的配置类对象
            self.data_list = data_list   # 接收传递过来的当前表的所有对象
    

    (3)给模板传递正确的数据

      由于模板接收的数据是header_list和new_data_list。需要给get_header和get_body函数添加返回值。

      同时在list_view中构建header_list和new_data_list变量:

    show_list = ShowList(self, data_list)  # 传入self,即将当前ModelStark的实例对象传给ShowList
    header_list = show_list.get_header()
    new_data_list = show_list.get_body()
    

    3、给查看页码添加分页

    (1)service/stark.py:

    from stark.utils.page import Pagination
    
    class ShowList(object):
        """展示页面类"""
        def __init__(self, config, data_list, request):
            self.config = config   # 接收传递过来的配置类对象
            self.data_list = data_list   # 接收传递过来的当前表的所有对象
            self.request = request
            # 分页
            data_count = self.data_list.count()
            current_page = int(self.request.GET.get("page", 1))  # 默认是第一页
            base_path = self.request.path
    
            self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=1, pager_count=11,)
            self.page_data = self.data_list[self.pagination.start:self.pagination.end]
        """代码省略"""
    
    
    class ModelStark(object):
        """代码省略"""
        def list_view(self, request):
            data_list = self.model.objects.all()  # 拿到对应表所有的对象
            show_list = ShowList(self, data_list, request)  # 传入self,即将当前ModelStark的实例对象传给ShowList
            header_list = show_list.get_header()
            new_data_list = show_list.get_body()
            # 构建一个查看url
            add_url = self.get_add_url()
            print("add_url", add_url)
            return render(request, "list_view.html", locals())
    

    (1)list_view函数中创建ShowList示例时多传入了一个request参数。ShowList拿到request后获取GET请求数据和请求路径:

    class ShowList(object):
        """展示页面类"""
        def __init__(self, config, data_list, request):
            self.config = config   # 接收传递过来的配置类对象
            self.data_list = data_list   # 接收传递过来的当前表的所有对象
            self.request = request   #  <WSGIRequest: GET '/stark/app01/book/?page=2'>
            # 分页
            data_count = self.data_list.count()
            current_page = int(self.request.GET.get("page", 1))  # 默认是第一页
            base_path = self.request.path   # /stark/app01/book/
    

    (2)实例化pagination,获取页码数据

      引入自定义分页组件,将参数传入完成pagination实例化。获取当前页码数据:

    class ShowList(object):
        """展示页面类"""
        def __init__(self, config, data_list, request):
            '''代码省略'''
            self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=1, pager_count=11,)
            print("data_list", self.data_list)   # data_list <QuerySet [<Book: python葵花宝典>, <Book: go>, <Book: java>]>
            self.page_data = self.data_list[self.pagination.start:self.pagination.end]
            print("page_data", self.page_data)   # page_data <QuerySet [<Book: python葵花宝典>]>
    
            '''代码省略'''
        def get_body(self):
            """构建表单数据"""
            new_data_list = []
            # for obj in self.data_list:
            for obj in self.page_data:   # 当前页面的数据
                '''代码省略'''
    

    (3)list_view.html添加分页

    <body>
    <h4>数据列表</h4>
    <div class="container">
        <div class="row">
            <div class="col-md-9"....代码省略..>
            <nav>
                <ul class="pagination">
                    {{ show_list.pagination.page_html|safe }}
                </ul>
            </nav>
        </div>
    </div>
    

    (4)显示效果如下:

      

    二、search查询

    1、在查看页面添加搜索框

    <h4>数据列表</h4>
    <div class="container">
        <div class="row">
            <div class="col-md-9">
                <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
                <form action="" class="pull-right">
                    <input type="text" name="q">
                    <button>搜索</button>
                </form>
                <table class="table table-bordered table-striped".....>
            </div>
            <nav....>
        </div>
    </div>
    

      输入查询内容后,点击搜索按钮,发送的get请求如下所示:

      

    2、查询匹配

    # -*- coding:utf-8 -*-
    __author__ = 'Qiushi Huang'
    
    
    from django.conf.urls import url
    from django.shortcuts import HttpResponse, render, redirect
    from django.utils.safestring import mark_safe
    from django.urls import reverse
    from stark.utils.page import Pagination
    
    
    class ShowList(object):
        """展示页面类"""
        def __init__(self, config, data_list, request):
            self.config = config   # 接收传递过来的配置类对象 ModelStark的实例对象
            self.data_list = data_list   # 接收传递过来的当前表的所有对象
            self.request = request   #  <WSGIRequest: GET '/stark/app01/book/?page=2'>
            # 分页
            data_count = self.data_list.count()
            current_page = int(self.request.GET.get("page", 1))  # 默认是第一页
            base_path = self.request.path   # /stark/app01/book/
    
            self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=1, pager_count=11,)
            print("data_list", self.data_list)   # data_list <QuerySet [<Book: python葵花宝典>, <Book: go>, <Book: java>]>
            self.page_data = self.data_list[self.pagination.start:self.pagination.end]
            print("page_data", self.page_data)   # page_data <QuerySet [<Book: python葵花宝典>]>
    
        def get_header(self):
            """构建表头"""
            header_list = []
            print("header", self.config.new_list_display())  # [checkbox ,"__str__", edit ,deletes]
    
            for field in self.config.new_list_display():
    
                if callable(field):
                    # 如果是函数
                    val = field(self, header=True)
                    header_list.append(val)
    
                else:
                    # 如果是字符串
                    if field == "__str__":
                        header_list.append(self.config.model._meta.model_name.upper())  # 当前模型表名
                    else:
                        # 如果不是"__str__"
                        # header_list.append(field)
                        val = self.config.model._meta.get_field(field).verbose_name
                        header_list.append(val)
            return header_list
    
        def get_body(self):
            """构建表单数据"""
            new_data_list = []
            # for obj in self.data_list:
            for obj in self.page_data:   # 当前页面的数据
                temp = []
    
                for field in self.config.new_list_display():  # ["__str__", ]   ["pk","name","age",edit]
    
                    if callable(field):
                        val = field(self.config, obj)
                    else:
                        val = getattr(obj, field)
                        if field in self.config.list_display_links:
                            # _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,))
                            _url = self.config.get_change_url(obj)
    
                            val = mark_safe("<a href='%s'>%s</a>" % (_url, val))
    
                    temp.append(val)
    
                new_data_list.append(temp)
            return new_data_list
    
    
    class ModelStark(object):
        """默认类,定制配置类"""
        list_display = ["__str__",]
        list_display_links = []
        modelform_class = []
        search_fields = []
    
        def __init__(self, model, site):
            self.model = model
            self.site = site
    
        # 删除、编辑,复选框
        def edit(self, obj=None, header=False):
            """编辑"""
            if header:
                # 如果是表头显示操作
                return "操作"
    
            _url = self.get_change_url(obj)
            return mark_safe("<a href='%s'>编辑</a>" % _url)
    
        def deletes(self, obj=None, header=False):
            """删除"""
            if header:
                # 如果是表头显示操作
                return "操作"
    
            _url = self.get_delete_url(obj)
            # return mark_safe("<a href='%s/change'>删除</a>" % obj.pk)
            return mark_safe("<a href='%s/'>删除</a>" % _url)
    
        def checkbox(self, obj=None, header=False):
            """复选框"""
            if header:
                # 如果是表头显示操作
                return mark_safe("<input id='choice' type='checkbox'>")
    
            return mark_safe("<input class='choice_item' type='checkbox'>")
    
        def get_modelform_class(self):
            """用来获取modelform类"""
            if not self.modelform_class:
                # 如果没有值
                from django.forms import ModelForm
                from django.forms import widgets as wid
    
                class ModelFormDemo(ModelForm):
                    class Meta:
                        model = self.model
                        fields = "__all__"
    
                return ModelFormDemo
            else:
                # 如果有值说明在用户已经自己定制过了,直接取值
                return self.modelform_class
    
        def add_view(self, request):
            ModelFormDemo = self.get_modelform_class()
            if request.method == "POST":
                form = ModelFormDemo(request.POST)
                if form.is_valid():  # 校验字段全部合格
                    form.save()
                    return redirect(self.get_list_url())  # 跳转到当前访问表的查看页面
    
                # (精髓)校验有错误返回页面,且包含了错误信息
                return render(request, "add_view.html", locals())
    
            form = ModelFormDemo()  # 实例化
            return render(request, "add_view.html", locals())
    
        def delete_view(self, request, id):
            url = self.get_list_url()
            if request.method == "POST":
                self.model.objects.filter(pk=id).delete()
                return redirect(url)
    
            # self.model.objects.filter(pk=id).delete()
            return render(request, "delete_view.html", locals())
    
        def change_view(self, request, id):
            """编辑视图"""
            ModelFormDemo = self.get_modelform_class()
            # 编辑对象
            edit_obj = self.model.objects.filter(pk=id).first()
    
            if request.method == "POST":
                form = ModelFormDemo(request.POST, instance=edit_obj)  # instance就是给这个记录更改为最新的数据
                if form.is_valid():  # 校验字段全部合格
                    form.save()
                    return redirect(self.get_list_url())  # 跳转到当前访问表的查看页面
    
                # (精髓)校验有错误返回页面,且包含了错误信息
                return render(request, "add_view.html", locals())
    
            form = ModelFormDemo(instance=edit_obj)   # 用instance放入编辑对象就有了编辑数据
    
            return render(request, "change_view.html", locals())
    
        def new_list_display(self):
            """返回新的列表"""
            temp = []
            temp.append(ModelStark.checkbox)  # 在列表中放一个checkbox名字
            temp.extend(self.list_display)  # 扩展进一个列表["pk","name","age"]
    
            if not self.list_display_links:
                # 如果没有值
                temp.append(ModelStark.edit)
    
            # temp.append(ModelStark.edit)    # edit函数名
            temp.append(ModelStark.deletes)   # deletes函数名
    
            return temp   # 返回新的列表
    
        def get_change_url(self,obj):
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,))
    
            return _url
    
        def get_delete_url(self, obj):
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,))
    
            return _url
    
        def get_add_url(self):
    
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_add" % (app_label, model_name))
    
            return _url
    
        def get_list_url(self):
    
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_list" % (app_label, model_name))
    
            return _url
    
        def get_search_condition(self, request):
            key_word = request.GET.get("q", "")   # 取不到q则直接取空
            self.key_word = key_word
            from django.db.models import Q
            search_connection = Q()
            if key_word:  # 判断key_word是否为空
                search_connection.connector = "or"  # 查询条件设置为或
                for search_field in self.search_fields:  # self.search_fields   # ['title', "price"]
                    search_connection.children.append((search_field + "__contains", key_word))
            return search_connection
    
        def list_view(self, request):
            # 获取search的Q对象
            search_condition = self.get_search_condition(request)
            # 筛选当前表获取的数据
            data_list = self.model.objects.all().filter(search_condition)
    
            # 获取showlist展示页面
            show_list = ShowList(self, data_list, request)
    
            header_list = show_list.get_header()
            new_data_list = show_list.get_body()
    
            # 构建一个查看url
            add_url = self.get_add_url()
            print("add_url", add_url)
            return render(request, "list_view.html", locals())
    
        def get_urls_2(self):
            temp = []
    
            # 用name取别名app名+model名+操作名可以保证别名不会重复
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
            temp.append(url(r"^add/", self.add_view, name="%s_%s_add" % (app_label, model_name)))
            temp.append(url(r"^(d+)/delete/", self.delete_view, name="%s_%s_delete" % (app_label, model_name)))
            temp.append(url(r"^(d+)/change/", self.change_view, name="%s_%s_change" % (app_label, model_name)))
            temp.append(url(r"^$", self.list_view, name="%s_%s_list" % (app_label, model_name)))
            return temp
    
        @property
        def urls_2(self):
            return self.get_urls_2(), None, None  # [], None, None
    
    
    class StarkSite(object):
        """site单例类"""
        def __init__(self):
            self._registry = {}
    
        def register(self, model, stark_class=None, **options):
            """注册"""
            if not stark_class:
                # 如果注册的时候没有自定义配置类,执行
                stark_class = ModelStark   # 配置类
    
            # 将配置类对象加到_registry字典中,键为模型类
            self._registry[model] = stark_class(model, self)   # _registry={'model':admin_class(model)}
    
        def get_urls(self):
            """构造一层url"""
            temp = []
            for model, stark_class_obj in self._registry.items():
                # model:一个模型表
                # stark_class_obj:当前模型表相应的配置类对象
    
                model_name = model._meta.model_name
                app_label = model._meta.app_label
    
                # 分发增删改查
                temp.append(url(r"^%s/%s/" % (app_label, model_name), stark_class_obj.urls_2))
                """
                   path('app01/userinfo/',UserConfig(Userinfo,site).urls2),
                   path('app01/book/',ModelStark(Book,site).urls2),
                """
    
            return temp
    
        @property
        def urls(self):
            return self.get_urls(), None, None
    
    
    site = StarkSite()    # 单例对象
    stark/service/stark.py

    (1)Q查询

      filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果需要执行更复杂的查询(例如OR 语句)可以使用Q对象可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询。

      在这里由于需要循环self.search_fields,且拿到的都是一个个字符串。所以需要使用Q对象实例化的用法:

    from .models import *
    
    def test(request):
        from django.db.models import Q
        # Q查询普通写法:
        ret = Book.objects.all().filter(Q(title="go")|Q(price=103))
        print("ret", ret)    # ret <QuerySet [<Book: go>]>
        # Q查询特殊用法:
        q = Q()
        q.connectiion = "or"
        q.children.append(("title", "go"))
        q.children.append(("price", 103))
        print("q", q)   # q (AND: ('title', 'yuan'), ('price', 123))
        return HttpResponse(ret, q) 
    

      Q查询特殊用法应用:

    class ModelStark(object):
        def list_view(self, request):
            key_word = request.GET.get("q")
    
            from django.db.models import Q
            search_connection = Q()
            search_connection.connector = "or"   # 查询条件设置为或
            for search_field in self.search_fields:   # self.search_fields   # ['title', "price"]
                search_connection.children.append((search_field, key_word))
    
            data_list = self.model.objects.all().filter(search_connection)
    
            # 获取showlist展示页面
            show_list = ShowList(self, data_list, request)
            header_list = show_list.get_header()
            new_data_list = show_list.get_body()
            # 构建一个查看url
            add_url = self.get_add_url()
            print("add_url", add_url)
            return render(request, "list_view.html", locals())
    

    (2)基于双下划线的模糊查询

    # __startwith: 以...开头
    ret = Book.objects.filter(title__startswith="py")
    print(ret)   # <QuerySet [<Book: python红宝书>]>
     
    # __contains:带有...字符
    ret = Book.objects.filter(title__contains="h")
    print(ret)   # <QuerySet [<Book: python红宝书>, <Book: php宝典>]>
    

      模糊查询应用:search_field+"__contains"

    class ModelStark(object):
        def list_view(self, request):
            key_word = request.GET.get("q")
            from django.db.models import Q
            search_connection = Q()
            if key_word:   # 判断key_word是否为空
                search_connection.connector = "or"   # 查询条件设置为或
                for search_field in self.search_fields:   # self.search_fields   # ['title', "price"]
                    search_connection.children.append((search_field + "__contains", key_word))
    
            # 获取当前表所有数据
            data_list = self.model.objects.all().filter(search_connection)
    

      查询效果:

      

    (3)在实例方法中封装模糊查询

    class ModelStark(object):
        def get_search_condition(self, request):
            key_word = request.GET.get("q")
            from django.db.models import Q
            search_connection = Q()
            if key_word:  # 判断key_word是否为空
                search_connection.connector = "or"  # 查询条件设置为或
                for search_field in self.search_fields:  # self.search_fields   # ['title', "price"]
                    search_connection.children.append((search_field + "__contains", key_word))
            return search_connection
    
        def list_view(self, request):
            # 获取search的Q对象
            search_condition = self.get_search_condition(request)
            # 筛选当前表获取的数据
            data_list = self.model.objects.all().filter(search_condition)
    
            # 获取showlist展示页面
            show_list = ShowList(self, data_list, request)
    
            header_list = show_list.get_header()
            new_data_list = show_list.get_body()
    
            # 构建一个查看url
            add_url = self.get_add_url()
            print("add_url", add_url)
            return render(request, "list_view.html", locals())
    

    (4)查询提交后,查询框依旧显示搜索的字段

      提交查询后相当于获取了一个新的页面,要显示搜索的字段,必须获取该字段并传到新页面中。

    <form action="" class="pull-right">
        <input type="text" name="q" value="{{ show_list.config.key_word }}">
        <button>搜索</button>
    </form>
    

       这里需要注意show_list这个变量,在ModelStark类中list_view实例方法中,实例化ShowList类时,传递了self,这个self是ModelStark的实例对象,而这个实例对象由ShowList用self.config接收。因此show_list是ShowList的实例对象,具备config属性,show_list.config就是ModelStark的实例对象,具备key_word实例属性。

      显示效果:

      

      如果没有输入任何内容直接搜索,搜索框会显示一个None,如果要只显示为空,需要在request.GET.get("q")做如下调整:

    class ModelStark(object):
        def get_search_condition(self, request):
            key_word = request.GET.get("q", "")   # 取不到q则直接取空
            self.key_word = key_word
            from django.db.models import Q
            search_connection = Q()
            if key_word:  # 判断key_word是否为空
                search_connection.connector = "or"  # 查询条件设置为或
                for search_field in self.search_fields:  # self.search_fields   # ['title', "price"]
                    search_connection.children.append((search_field + "__contains", key_word))
            return search_connection
    

    3、自定义配置类中配置search_fields则显示搜索框,否则不显示

      在list_view.html中先通过if判断show_list.config.search_fields是否有值,有值则显示搜索框,否则不显示。

    <h4>数据列表</h4>
    <div class="container">
        <div class="row">
            <div class="col-md-9">
                {# <a href="add/" class="btn btn-primary">添加数据</a> #}
                <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
                {% if show_list.config.search_fields %}
                    <form action="" class="pull-right">
                        <input type="text" name="q" value="{{ show_list.config.key_word }}">
                        <button>搜索</button>
                    </form>
                {% endif %}
                <table class="table table-bordered table-striped"......>
            </div>
            <nav>
                <ul class="pagination">
                    {{ show_list.pagination.page_html|safe }}
                </ul>
            </nav>
        </div>
    </div>
    

      在自定义配置类注释掉search_fields字段。

    app01/stark.py:

    class BookConfig(ModelStark):
        list_display = ["title", "price", "publishDate"]
        modelform_class = BookModelForm
        # search_fields = ['title', "price"]
    
    site.register(Book, BookConfig)
    

      页面显示:

      

    三、actions——批量处理

    1、admin组件实现actions批量处理

    app01/admin.py:

    from django.contrib import admin
    from .models import Book
    
    class BookConfig(admin.ModelAdmin):
        list_display = ["title", "price"]
    
        def patch_init(self, request, queryset):
            print("queryset", queryset)
            # queryset <QuerySet [<Book: java>, <Book: python葵花宝典>]>
            queryset.update(price=100)
    
        patch_init.short_description = "批量初始化"
        actions = [patch_init]
    
    admin.site.register(Book, BookConfig)
    

      注意在这里可以通过patch_init.short_description设置批量操作中文名称。

    批量处理前:

      

    批量处理后:

      

    2、在list_view.html中添加action选择框,重构form表单

    <div class="container">
        <div class="row">
            <div class="col-md-9">
                {# <a href="add/" class="btn btn-primary">添加数据</a> #}
                <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
                {% if show_list.config.search_fields %}
                    <form action="" class="pull-right">
                        <input type="text" name="q" value="{{ show_list.config.key_word }}">
                        <button>搜索</button>
                    </form>
                {% endif %}
                <form action="">
                    <select name="action" id="" style=" 200px; padding: 5px 8px; display: inline-block">
                        <option value="">xxxxx</option>
                    </select>
                    <button type="submit" class="btn-info">Go</button>
                    <table class="table table-bordered table-striped"......>
                    <nav.....>
                </form>
            </div>
        </div>
    </div>
    

      注意页面中有两个表单,一个是搜索框的表单,另一个则是包含了aciton、表格、分页。

      页面显示效果如下所示:

      

    3、自定义配置actions

    (1)构建自定义配置类actions的函数

     app01/stark.py:

    class BookConfig(ModelStark):
        list_display = ["title", "price", "publishDate"]
        modelform_class = BookModelForm
        search_fields = ['title', "price"]
    
        def patch_init(self, request, queryset):
            print(queryset)
    
        patch_init.short_description = "批量初始化"
        actions = [patch_init]
    
    site.register(Book, BookConfig)
    

    (2)处理actions批量操作函数

    /stark/service/stark.py:

    class ShowList(object):
        """展示页面类"""
        def __init__(self, config, data_list, request):
            self.config = config   # 接收传递过来的配置类对象 ModelStark的实例对象
            self.data_list = data_list   # 接收传递过来的当前表的所有对象
            self.request = request   #  <WSGIRequest: GET '/stark/app01/book/?page=2'>
            # 分页
            data_count = self.data_list.count()
            current_page = int(self.request.GET.get("page", 1))  # 默认是第一页
            base_path = self.request.path   # /stark/app01/book/
    
            self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=3, pager_count=11,)
            self.page_data = self.data_list[self.pagination.start:self.pagination.end]
          
            # actions
            self.actions = self.config.actions   # 拿到配置好的函数对象列表  [patch_init,]
        
        def get_action_list(self):
            temp = []
            for action in self.actions:
                temp.append({
                    "name": action.__name__,    # 函数.__name__:拿到函数名
                    "desc": action.short_description
                })  # [{"name": "patch_init", "desc": "批量处理"}]
            return temp
        """代码省略"""
    
    class ModelStark(object):
        """默认类,定制配置类"""
        list_display = ["__str__",]
        list_display_links = []
        modelform_class = []
        search_fields = []
        actions = []   # 调用self.actions拿到的是函数
        """代码省略"""
    

      在ModelStark类中默认actions= [],因此在中实例化ShowList时,通过self将actions传递到ShowList类对象,以self.config.actions拿到配置好的函数对象列表交给get_action_list函数处理。

      在get_action_list中循环处理函数对象列表,通过函数对象.__name__方式拿到函数名;通过函数对象.short_description拿到描述别名。以字典的形式保存在列表中返回给show_list对象交给页面进行渲染。

    (3)进一步构建批量操作表单

    <form action="" method="post">
        {% csrf_token %}
        <select name="action" id="" style=" 200px; padding: 5px 8px; display: inline-block">
            <option value="">-----------</option>
            {% for item in show_list.get_action_list %}
                <option value="{{ item.name }}">{{ item.desc }}</option>
            {% endfor %}
        </select>
        <button type="submit" class="btn-info">Go</button>
        <table class="table table-bordered table-striped"......>
        <nav>
            <ul class="pagination">
                {{ show_list.pagination.page_html|safe }}
            </ul>
        </nav>
    </form>
    

      show_list.get_action_list拿到函数的返回值temp,循环拿到的item为一个个字典,键为name的是函数名,键为desc的是描述别名。

    (4)显示效果

      

    3、实现点选提交

    (1)重构checkbox标签

      点选批量操作需要拿到当前操作对象的pk值,也需要判断哪些标签被点选提交。

    class ModelStark(object):
        """代码省略"""
        def checkbox(self, obj=None, header=False):
            """复选框"""
            if header:
                # 如果是表头显示操作
                return mark_safe("<input id='choice' type='checkbox'>")
    
            return mark_safe("<input class='choice_item' type='checkbox' name='selected_pk' value='%s'>" % obj.pk)
    

     (2)list_view处理post请求

    class ModelStark(object):
        def list_view(self, request):
            if request.method == "POST":    # action
                print("POST:", request.POST)
                action = request.POST.get("action")
                selected_pk = request.POST.getlist("selected_pk")  # 拿到列表
                # 反射
                # self这里是配置类BookConfig,要在类中找到对应的函数
                action_func = getattr(self, action)   # patch_init
                # 拿到选中状态的pk值对象
                queryset = self.model.objects.filter(pk__in=selected_pk)  # <QuerySet [<Book: go>]>
                action_func(request, queryset)
    
            # 获取search的Q对象
            search_condition = self.get_search_condition(request)
            # 筛选当前表获取的数据
            data_list = self.model.objects.all().filter(search_condition)
    
            # 获取showlist展示页面
            show_list = ShowList(self, data_list, request)
    
            header_list = show_list.get_header()
            new_data_list = show_list.get_body()
    
            # 构建一个查看url
            add_url = self.get_add_url()
            print("add_url", add_url)
            return render(request, "list_view.html", locals())
    

      在这里POST请求处理不需要返回值,批量初始化后,数据库已经更改,代码顺着下来紧接着就是查询拿到新的页面。

    (3)配置校验

    class BookConfig(ModelStark):
        list_display = ["title", "price", "publishDate"]
        modelform_class = BookModelForm
        search_fields = ['title', "price"]
    
        def patch_init(self, request, queryset):
            print(queryset)
            queryset.update(price=123)
    
        patch_init.short_description = "批量初始化"
    
        actions = [patch_init]
    
    
    site.register(Book, BookConfig)
    app01/stark.py

      显示效果:

      

    4、添加admin批量操作自带的delete功能

    class ShowList(object):
        def __init__(self, config, data_list, request):
            self.config = config   # 接收传递过来的配置类对象 ModelStark的实例对象
            self.data_list = data_list   # 接收传递过来的当前表的所有对象
            self.request = request   #  <WSGIRequest: GET '/stark/app01/book/?page=2'>
            # 分页
            data_count = self.data_list.count()
            current_page = int(self.request.GET.get("page", 1))  # 默认是第一页
            base_path = self.request.path   # /stark/app01/book/
    
            self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=3, pager_count=11,)
            self.page_data = self.data_list[self.pagination.start:self.pagination.end]
    
            # actions
            # self.actions = self.config.actions   # 拿到配置好的函数对象列表  [patch_init,]
            self.actions = self.config.new_actions()   # 拿到方法运行的返回结果
    
        def get_action_list(self):
            """获取自定义批量操作"""
            temp = []
            for action in self.actions:
                temp.append({
                    "name": action.__name__,    # 函数.__name__:拿到函数名
                    "desc": action.short_description
                })  # [{"name": "patch_init", "desc": "批量处理"}]
            return temp
    
    
    class ModelStark(object):
        """默认类,定制配置类"""
        list_display = ["__str__",]
        list_display_links = []
        modelform_class = []
        search_fields = []
        actions = []  # 调用self.actions拿到的是函数
    
        def __init__(self, model, site):
            self.model = model
            self.site = site
    
        def patch_delete(self, request, queryset):
            """默认批量删除操作"""
            queryset.delete()
    
        patch_delete.short_description = "批量删除"
    
        def new_actions(self):
            """返回所有批量操作"""
            temp = []
            # 默认添加批量删除
            temp.append(ModelStark.patch_delete)
            # 添加自定义action
            temp.extend(self.actions)
            return temp
    

      在new_actions实例方法中,首先可以通过ModelStark.patch_delete固定拿到默认需要添加的批量删除方法。其次ModelStark类中默认actions=[],因此在自定义配置类有配置actions时,self.actions拿到默认配置类配置的列表,如果没有配置拿到空列表。然后通过extend函数扩展列表返回所有批量操作函数。

      ShowList实例化时,self.actions属性通过self.config.new_actions()拿到new_actions返回结果。然后在模板上就可以通过show_list.config.actions渲染所有的actions操作了。

      显示效果:

    1)自定义配置类没有配置actions:

      

    2)自定义配置类配置了actions:

  • 相关阅读:
    Java的内存结构(Memory Structure)和垃圾收集(Garbage Collection)图解
    走遍天下的三大vb控制结构
    程序员快速阅读,绝对不是神话
    Android4.0.3源码分析——开机流程之Zygote
    云端的天使
    提高班的“伞”
    Android 4.0.3 源代码结构分析(一)
    如何在Java中选择Map/List/Set
    关于Hadoop中reducer端combiner的一些思考
    vb添加GIF动态图片
  • 原文地址:https://www.cnblogs.com/xiugeng/p/9515102.html
Copyright © 2020-2023  润新知