stark——分頁、search、actions

1、分頁

一、引入自定義分頁組件

  在/stark目錄下建立utils工具包目錄,複製page.py到該目錄下,文件中有以前自定義的分頁組件。php

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

二、整合展現數據showlist類實現代碼解耦

  將list_view函數中的構建表頭代碼挪移到ShowList類的get_header函數下,將將list_view函數中的構建表單代碼挪移到ShowList類的get_body函數下。html

/stark/serivce/stark.py:java

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實例化,在實例化時傳入:python

  self:即當前ModelStark的實例對象;data_list:對應表全部的對象。數據庫

(2)在新的類ShowList經過__init__方法來接收者兩個參數:django

class ShowList(object):
    """展現頁面類"""
    def __init__(self, config, data_list):
        self.config = config   # 接收傳遞過來的配置類對象
        self.data_list = data_list   # 接收傳遞過來的當前表的全部對象

(3)給模板傳遞正確的數據app

  因爲模板接收的數據是header_list和new_data_list。須要給get_header和get_body函數添加返回值。ide

  同時在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()

三、給查看頁碼添加分頁

(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)顯示效果以下:

  

2、search查詢

一、在查看頁面添加搜索框

<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請求以下所示:

  

二、查詢匹配

# -*- 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

三、自定義配置類中配置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)

  頁面顯示:

  

3、actions——批量處理

一、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設置批量操做中文名稱。

批量處理前:

  

批量處理後:

  

二、在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="width: 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、表格、分頁。

  頁面顯示效果以下所示:

  

三、自定義配置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="width: 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)顯示效果

  

三、實現點選提交

(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

  顯示效果:

  

四、添加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:

相關文章
相關標籤/搜索