stark——快速過濾list_filter

1、獲取過濾字段

一、給自定義配置類配置list_filter

  app01/stark.py:css

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]
    list_filter = ["publish", "authors", ]   # 一對多、多對多

site.register(Book, BookConfig)

二、構建實例方法獲取過濾字段

class ShowList(object):
    """展現頁面類"""
    def __init__(self, config, data_list, request):...

    def get_filter_linktags(self):
        """獲取過濾字段"""
        link_list = {}
        print("list_filter", self.config.list_filter)   # list_filter ['publish', 'authors']
        for filter_field in self.config.list_filter:
            print(filter_field)   # 'publish'  'authors'
            # 獲取字段對象
            filter_field_obj = self.config.model._meta.get_field(filter_field)
            print(filter_field_obj)  # app01.Book.publish   app01.Book.authors
            print(type(filter_field_obj))
            """
            <class 'django.db.models.fields.related.ForeignKey'>
            <class 'django.db.models.fields.related.ManyToManyField'>
            from django.db.models.fields.related import ForeignKey
            from django.db.models.fields.related import ManyToManyField
            """
            # 拿到關聯表下的全部數據
            # print("rel...", filter_field_obj.rel.to.objects.all())   # 版本問題失效
            print("rel...", filter_field_obj.related_model.objects.all())
            """
            rel... <QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>
            rel... <QuerySet [<Author: alex>, <Author: egon>]>
            """
        return link_list

class ModelStark(object):
    """默認類,定製配置類"""
    list_display = ["__str__",]
    list_display_links = []
    modelform_class = []
    search_fields = []
    actions = []  # 調用self.actions拿到的是函數
    list_filter = []

 注意:html

(1)獲取自定義配置類定義的list_filter列表

  ShowList類對象,經過self.config.list_filter能夠拿到當前訪問頁面對象自定義配置類配置的list_filter列表。java

(2)根據字段字符串獲取模型字段對象

filter_field_obj = self.config.model._meta.get_field(filter_field)
model_name = self.config.model._meta.model_name  # 模型名 book
app_label = self.config.model._meta.app_label    # app名 app01

(3)根據一對多,多對多對象關聯關係,獲得關聯模型表和數據

# 拿到關聯表下的全部數據
# print("rel...", filter_field_obj.rel.to.objects.all())   # 版本問題失效(filter_field_obj.rel.to是關聯模型表)
print("rel...", filter_field_obj.related_model.objects.all())  # 拿到對象下的關聯數據
"""
rel... <QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>
rel... <QuerySet [<Author: alex>, <Author: egon>]>
"""

2、根據拿到的對象關聯數據完成數據組織

一、get_filter_linktags方法組織返回連接字典

class ShowList(object):
    """展現頁面類"""
    def get_filter_linktags(self):
        """獲取過濾字段"""
        link_dic = {}
        print("list_filter", self.config.list_filter)   # list_filter ['publish', 'authors']
        for filter_field in self.config.list_filter:
            print(filter_field)   # 'publish'  'authors'
            # 獲取字段對象
            filter_field_obj = self.config.model._meta.get_field(filter_field)
            print(filter_field_obj)  # app01.Book.publish   app01.Book.authors
            # 拿到關聯表下的全部數據
            # print("rel...", filter_field_obj.rel.to.objects.all())   # 版本問題失效
            # print("rel...", filter_field_obj.related_model.objects.all())  # <QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>

            data_list = filter_field_obj.related_model.objects.all()  # <QuerySet [<Publish: 蘋果出版社>
            temp = []
            for obj in data_list:   # obj是每個對象
                # print(obj)  # 蘋果出版社 香蕉出版社  alex  egon
                # print(type(obj))   # <class 'app01.models.Publish'>  <class 'app01.models.Author'>
                link_tag = "<a href=>%s</a>" % str(obj)
                # print(link_tag)  # <a href=>蘋果出版社</a>

                temp.append(link_tag)

            link_dic[filter_field] = temp
            # print(link_dic)   # {'publish': ['<a href=>蘋果出版社</a>', '<a href=>香蕉出版社</a>'], 'authors': ['<a href=>alex</a>', '<a href=>egon</a>']}

        return link_dic

  這裏最重要就是理清楚每一個變量的類型和含義:python

self.config.list_filter——['publish', 'authors']
filter_field_obj—— app01.Book.publish、app01.Book.authors
filter_field_obj.related_model.objects.all()——<QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>、<QuerySet [<Author: alex>, <Author: egon>]>

obj——蘋果出版社 香蕉出版社  alex  egon
     數據類型:<class 'app01.models.Publish'>  <class 'app01.models.Author'>
link_tag——<a href=>蘋果出版社</a>

link_dic——{'publish': ['<a href=>蘋果出版社</a>', '<a href=>香蕉出版社</a>'], 'authors': ['<a href=>alex</a>', '<a href=>egon</a>']}

二、list_view.html構建顯示

<h4>數據列表</h4>
<div class="container">
    <div class="row">
        <div class="col-md-9".....>
        <div class="col-md-3">
            <div class="filter">
                <h4>Filter</h4>
                {% for filter_field, linktags in show_list.get_filter_linktags.items %}
                    <div>
                        <p>{{ filter_field }}</p>
                        {% for link in linktags %}
                            <p>{{ link|safe }}</p>
                        {% endfor %}
                    </div>
                {% endfor %}
            </div>
        </div>
    </div>
</div>

  注意這裏使用{{link|safe}}來實現取消轉義。顯示效果以下:django

  

3、標籤href處理

class ShowList(object):
    """展現頁面類"""

    def get_filter_linktags(self):
        """獲取過濾字段"""
        link_dic = {}
        print("list_filter", self.config.list_filter)   # list_filter ['publish', 'authors']

        for filter_field in self.config.list_filter:
            """循環每個過濾字段"""
            import copy
            # self.request.GET   # GET請求的全部數據
            params = copy.deepcopy(self.request.GET)

            print(filter_field)   # 'publish'  'authors'
            # 獲取字段對象
            filter_field_obj = self.config.model._meta.get_field(filter_field)
            print(filter_field_obj)  # app01.Book.publish   app01.Book.authors
            # 拿到關聯表下的全部數據
            # print("rel...", filter_field_obj.rel.to.objects.all())   # 版本問題失效
            # print("rel...", filter_field_obj.related_model.objects.all())  # <QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>

            data_list = filter_field_obj.related_model.objects.all()  # <QuerySet [<Publish: 蘋果出版社>
            temp = []
            for obj in data_list:   # obj是每個對象
                """循環每個過濾字段關聯的數據"""
                # 構成一個新字典 過濾字段:當前對象主鍵值
                params[filter_field + "__id"] = obj.pk
                # 利用urlencode將鍵值對轉化爲a=1&b=2的格式
                _url = params.urlencode()

                # print(obj)  # 蘋果出版社 香蕉出版社  alex  egon
                # print(type(obj))   # <class 'app01.models.Publish'>  <class 'app01.models.Author'>
                link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj))
                # print(link_tag)  # <a href=>蘋果出版社</a>

                temp.append(link_tag)

            link_dic[filter_field] = temp
            # print(link_dic)   # {'publish': ['<a href=>蘋果出版社</a>', '<a href=>香蕉出版社</a>'], 'authors': ['<a href=>alex</a>', '<a href=>egon</a>']}

        return link_dic

注意:數組

一、copy.deepcopy()使用

  • 直接賦值:其實就是對象的引用(別名)。app

  • 淺拷貝(copy):拷貝父對象,不會拷貝對象的內部的子對象。函數

  • 深拷貝(deepcopy): copy 模塊的 deepcopy 方法,徹底拷貝了父對象及其子對象。url

  這裏每循環一次過濾字段都會從新建立一個params。保證按鈕對應路徑的惟一性。spa

二、利用urlencode將鍵值對轉化爲a=1&b=2的格式

  這裏主要是應爲發送的是get請求,請求數據必須是a=1&b=2的格式。

三、params = copy.deepcopy(self.request.GET)意義

   self.request.GET獲取的是GET請求的全部數據,屢次點擊能夠實現get請求數據的拼接。打印params,在頁面點擊訪問,控制檯輸出以下:

params <QueryDict: {}>    ——沒有點擊a標籤
params <QueryDict: {'authors__id': ['1']}>   ——第一次點擊
params <QueryDict: {'authors__id': ['1'], 'publish__id': ['2']}>   ——第二次點擊

  

4、a標籤點擊後顏色變化

一、前置準備

(1)將過濾字段顯示爲大寫

{% for filter_field, linktags in show_list.get_filter_linktags.items %}
    <div class="well">
        {# upper方法改成大寫 #}
        <p>{{ filter_field.upper }}</p>
        {% for link in linktags %}
            <p>{{ link|safe }}</p>
        {% endfor %}
    </div>
{% endfor %}

(2)取消a標籤顏色

<style>
    .filter a {
        text-decoration: none;   /* 取消a標籤顏色 */
        color: grey;
    }
</style>

二、對當前get請求數據進行判斷

class ShowList(object):
    def get_filter_linktags(self):
        """獲取過濾字段"""
        link_dic = {}
        print("list_filter", self.config.list_filter)   # list_filter ['publish', 'authors']

        for filter_field in self.config.list_filter:
            """循環每個過濾字段"""
            import copy
            # self.request.GET   # GET請求的全部數據
            params = copy.deepcopy(self.request.GET)
            print("params", params)

            # cid是當前字段傳過來的值
            cid = self.request.GET.get(filter_field + "__id", 0)
            # 沒有值的時候默認爲None,None是不能進行int()轉換的,所以在這裏給它設置默認值爲0

            # print(filter_field)   # 'publish'  'authors'
            # 獲取字段對象
            filter_field_obj = self.config.model._meta.get_field(filter_field)

            data_list = filter_field_obj.related_model.objects.all()  # <QuerySet [<Publish: 蘋果出版社>
            temp = []
            for obj in data_list:   # obj是每個對象
                """循環每個過濾字段關聯的數據"""
                # 構成一個新字典 過濾字段:當前對象主鍵值
                params[filter_field + "__id"] = obj.pk
                # 利用urlencode將鍵值對轉化爲a=1&b=2的格式
                _url = params.urlencode()

                if int(cid) == obj.pk:
                    # get請求數據int轉換後與對象主鍵值匹配,匹配成功添加active類
                    link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, str(obj))
                else:
                    link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj))
                temp.append(link_tag)
            link_dic[filter_field] = temp

        return link_dic

給模板添加樣式:

<style>
    .filter a {
        text-decoration: none;   /* 取消a標籤顏色 */
        color: grey;
    }
    .active {
        color: red!important;  /* 提高優先級 */
    }
</style>

注意:

(1)cid是當前get請求傳遞的值

cid = self.request.GET.get(filter_field + "__id", 0)

  須要注意的是在get請求沒有值的時候,默認值是None,可是None是不能進行int()轉換的,所以在這裏給它設置默認值0.

(2)根據get請求的值和對象主鍵比對,給a標籤添加avtice類

if int(cid) == obj.pk:
    # get請求數據int轉換後與對象主鍵值匹配,匹配成功添加active類
    link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, str(obj))
else:
    link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj))

(3)顯示效果

  

5、過濾器添加all按鈕取消過濾

class ShowList(object):
    def get_filter_linktags(self):
        """獲取過濾字段"""
        link_dic = {}
        print("list_filter", self.config.list_filter)   # list_filter ['publish', 'authors']

        for filter_field in self.config.list_filter:
            """循環每個過濾字段"""
            import copy
            # self.request.GET   # GET請求的全部數據
            params = copy.deepcopy(self.request.GET)
            print("params", params)   # <QueryDict: {'publish__id': ['1']}>
            # cid是當前字段傳過來的值
            cid = self.request.GET.get(filter_field + "__id", 0)
            # 沒有值的時候默認爲None,None是不能進行int()轉換的,所以在這裏給它設置默認值爲0

            # 獲取字段對象
            filter_field_obj = self.config.model._meta.get_field(filter_field)

            data_list = filter_field_obj.related_model.objects.all()  # <QuerySet [<Publish: 蘋果出版社>
            temp = []

            # 處理all標籤
            if params.get(filter_field + "__id"):
                del params[filter_field + "__id"]
                temp.append("<a href='?%s'>all</a>" % params.urlencode())
            else:
                temp.append("<a class='active' href='#'>all</a>")  # 默認是all的狀態

            # 處理數據標籤
            for obj in data_list:   # obj是每個對象
                """循環每個過濾字段關聯的數據"""
                # 構成一個新字典 過濾字段:當前對象主鍵值
                params[filter_field + "__id"] = obj.pk
                # 利用urlencode將鍵值對轉化爲a=1&b=2的格式
                _url = params.urlencode()

                if int(cid) == obj.pk:
                    # get請求數據int轉換後與對象主鍵值匹配,匹配成功添加active類
                    link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, str(obj))
                else:
                    link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj))

                temp.append(link_tag)

            link_dic[filter_field] = temp

        return link_dic

  注意:

一、在處理數據標籤前,在temp臨時數組中添加all的<a>標籤

# 處理all標籤
if params.get(filter_field + "__id"):
    del params[filter_field + "__id"]
    temp.append("<a href='?%s'>all</a>" % params.urlencode())
else:
    temp.append("<a class='active' href='#'>all</a>")  # 默認是all的狀態

  點擊a標籤因爲href沒有在?前填任何值,默認是將get請求發送給原函數處理。

  params是深度複製了get請求的數據,所以每次點擊a標籤都在添加params的值:

params <QueryDict: {}>    ——沒有點擊a標籤
params <QueryDict: {'authors__id': ['1']}>   ——第一次點擊
params <QueryDict: {'authors__id': ['1'], 'publish__id': ['2']}>   ——第二次點擊

  params.get(filter_field + "__id")  就能夠拿到對應的authors__id和publish__id.若是if判斷拿不到值,說明尚未進行過濾,添加帶有active類的a標籤:<a class='active' href='#'>all</a>。all標籤顯示爲激活狀態。

  若是if判斷有值,經過del方法清除對應的params中的值,添加不帶有active類的a標籤:

temp.append("<a href='?%s'>all</a>" % params.urlencode())

二、params.urlencode解析

# 訪問http://127.0.0.1:8000/stark/app01/book/?authors__id=1&publish__id=1

print("urlencode", params.urlencode)
print("_url", params.urlencode())
print("params", params)

"""
urlencode <bound method QueryDict.urlencode of <QueryDict: {'authors__id': ['1'], 'publish__id': ['1']}>>
_url authors__id=1&publish__id=1
params <QueryDict: {'authors__id': ['1'], 'publish__id': ['1']}>
"""

三、刪改params不是修改get請求數據,而是修改a標籤href值(本質)

  經過點擊按鈕修改href值,修改每次發送的get請求數據。

  

  此時查看PUBLISH下的all按鈕:

  

  此時查看PUBLISH下的香蕉出版社:

  

6、過濾實現

一、刪除filter_field後面拼接的"__id"

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,)
        # 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葵花寶典>]>

        # actions
        # self.actions = self.config.actions   # 拿到配置好的函數對象列表  [patch_init,]
        self.actions = self.config.new_actions()   # 拿到方法運行的返回結果

    def get_filter_linktags(self):
        """獲取過濾字段"""
        link_dic = {}
        print("list_filter", self.config.list_filter)   # list_filter ['publish', 'authors']

        for filter_field in self.config.list_filter:
            """循環每個過濾字段"""
            import copy
            # self.request.GET   # GET請求的全部數據
            params = copy.deepcopy(self.request.GET)
            print("params", params)   # <QueryDict: {'publish__id': ['1']}>
            # cid是當前字段傳過來的值
            cid = self.request.GET.get(filter_field, 0)
            # 沒有值的時候默認爲None,None是不能進行int()轉換的,所以在這裏給它設置默認值爲0

            # print(filter_field)   # 'publish'  'authors'
            # 獲取字段對象
            filter_field_obj = self.config.model._meta.get_field(filter_field)
            # print(filter_field_obj)  # app01.Book.publish   app01.Book.authors
            # 拿到關聯表下的全部數據
            # print("rel...", filter_field_obj.rel.to.objects.all())   # 版本問題失效
            # print("rel...", filter_field_obj.related_model.objects.all())  # <QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>

            data_list = filter_field_obj.related_model.objects.all()  # <QuerySet [<Publish: 蘋果出版社>
            temp = []

            # 處理all標籤
            if params.get(filter_field):
                print("_url", params.urlencode)
                del params[filter_field]
                temp.append("<a href='?%s'>all</a>" % params.urlencode())
            else:
                temp.append("<a class='active' href='#'>all</a>")  # 默認是all的狀態

            # 處理數據標籤
            for obj in data_list:   # obj是每個對象
                """循環每個過濾字段關聯的數據"""
                # 構成一個新字典 過濾字段:當前對象主鍵值
                params[filter_field] = obj.pk
                # 利用urlencode將鍵值對轉化爲a=1&b=2的格式
                _url = params.urlencode()

                if int(cid) == obj.pk:
                    # get請求數據int轉換後與對象主鍵值匹配,匹配成功添加active類
                    link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, str(obj))
                else:
                    # print(obj)  # 蘋果出版社 香蕉出版社  alex  egon
                    # print(type(obj))   # <class 'app01.models.Publish'>  <class 'app01.models.Author'>
                    link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj))
                    # print(link_tag)  # <a href=>蘋果出版社</a>

                temp.append(link_tag)

            link_dic[filter_field] = temp
            # print(link_dic)   # {'publish': ['<a href=>蘋果出版社</a>', '<a href=>香蕉出版社</a>'], 'authors': ['<a href=>alex</a>', '<a href=>egon</a>']}

        return link_dic

二、構建filter的Q對象(過濾條件)

class ModelStark(object):
    def get_filter_condition(self, request):
        """拿到過濾條件"""
        filter_condition = Q()  # 默認查詢條件爲且 and

        for filter_field, val in request.GET.items():   # 過濾字段、查詢的值  去除fitler_field拼接的__id
            if filter_field in self.list_filter:    # 只處理filter過濾列表的鍵值(分頁等排除)
                filter_condition.children.append((filter_field, val))

        return filter_condition

  注意get_filter_condition只處理filter過濾列表鍵值,須要將分頁等請求數據排除。

三、在list_view方法中獲取filter的Q對象完成過濾

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)

        # 獲取filter構建Q對象
        filter_condition = self.get_filter_condition(request)

        # 篩選當前表獲取的數據
        data_list = self.model.objects.all().filter(search_condition).filter(filter_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())

  注意這裏是運用了鏈式操做,二次過濾。過濾效果顯示以下:

    

7、一對多、多對多字段渲染處理

一、添加一對多、多對多字段 到list_display

app01/stark.py:

class BookConfig(ModelStark):
    list_display = ["title", "price", "publishDate", "publish", "authors"]
    list_display_links = ["title"]
    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]
    list_filter = ["publish", "authors", ]   # 一對多、多對多

site.register(Book, BookConfig)

  publish是一對多字段、authors是多對多字段。頁面顯示以下:

  

能夠看到多對多字段沒法正常顯示,這個由於在service/stark.py中

class ShowList(object):
    """展現頁面類"""
    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

  get_body方法,val = getattr(obj, field)拿到的是關聯對象,在一對1、一對多狀況下,利用模型定了__str__能夠正常顯示名稱,可是卻沒法處理多對多的狀況。

二、多對多字段處理

class ShowList(object):
    """展現頁面類"""
    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:
                    from django.db.models.fields.related import ManyToManyField
                    field_obj = self.config.model._meta.get_field(field)   # 拿到字段對象
                    if isinstance(field_obj, ManyToManyField):  # 判斷是不是多對多
                        # 反射處理  增長.all
                        # 多對多的狀況  obj.field.all()
                        ret = getattr(obj, field).all()  # <QuerySet [<Author: alex>, <Author: egon>]>
                        t = []
                        for obj in ret:
                            t.append(str(obj))
                        val = ",".join(t)   # 用join方法實現拼接   alex,egon

                    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

  顯示效果:

  

 

  注意:

(1)引入多對多類,利用isinstance判斷對象是不是多對多對象

from django.db.models.fields.related import ManyToManyField
field_obj = self.config.model._meta.get_field(field)   # 拿到字段對象
if isinstance(field_obj, ManyToManyField):  # 判斷是不是多對多

(2)利用反射處理多對多的狀況

# 反射處理  增長.all
# 多對多的狀況  obj.field.all()
ret = getattr(obj, field).all()  # <QuerySet [<Author: alex>, <Author: egon>]>
t = []
for obj in ret:
    t.append(str(obj))
val = ",".join(t)   # 用join方法實現拼接   alex,egon

(3)注意getattr(obj, field) 和getattr(obj, field).all()的區別

print("ret",getattr(obj, field))   # ret app01.Author.None
print("ret", getattr(obj, field).all())  # ret <QuerySet [<Author: alex>, <Author: egon>]>

(4)join()方法

  用於將序列中的元素以指定的字符鏈接生成一個新的字符串。

str = "-"
seq = ("a", "b", "c")    # 字符串序列
print str.join( seq )    # a-b-c

8、普通字段篩選

一、給list_filter添加普通字段"title"

  app01/stark.py:

class BookConfig(ModelStark):
    list_display = ["title", "price", "publishDate", "publish", "authors"]
    list_display_links = ["title"]
    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]
    list_filter = ["title", "publish", "authors", ]   # 普通字段、一對多、多對多

site.register(Book, BookConfig)

  添加後訪問頁面直接報錯:

  

  這是因爲在ShowList類get_filter_linktags方法中:

# 獲取字段對象
filter_field_obj = self.config.model._meta.get_field(filter_field)
# 關聯表下全部數據
data_list = filter_field_obj.related_model.objects.all()  # <QuerySet [<Publish: 蘋果出版社>

  data_list這種取法只適用於一對一和一對多的狀況。

二、處理過濾字段對象

from django.db.models.fields.related import ManyToManyField, ForeignKey

class ShowList(object):
    """展現頁面類"""
    def get_filter_linktags(self):
        """獲取過濾字段"""
        link_dic = {}
        print("list_filter", self.config.list_filter)   # list_filter ['publish', 'authors']
        for filter_field in self.config.list_filter:
            """循環每個過濾字段"""
            import copy
            params = copy.deepcopy(self.request.GET)
            cid = self.request.GET.get(filter_field, 0)
            # 獲取字段對象
            filter_field_obj = self.config.model._meta.get_field(filter_field)        

            if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
                data_list = filter_field_obj.related_model.objects.all()  # <QuerySet [<Publish: 蘋果出版社>
            else:
                # 普通字段直接查詢
                data_list = self.config.model.objects.all().values("pk", filter_field) # 主鍵值  字段對象值

  引入ForeignKey和ManyToManyField類,利用isinstance判斷是不是一對多、多對多對象。若是不是就是普通字段,直接查詢處理。

三、處理數據標籤對data_list作對應處理

# 處理數據標籤
for obj in data_list:   # obj是每個對象
    """循環每個過濾字段關聯的數據"""
    if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
        # <QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>
        pk = obj.pk
        text = str(obj)
    else:
        # 列表裏面套着字典 data_list=[{"pk":1, "title":"go"},....]
        pk = obj.get("pk")
        text = obj.get(filter_field)

    # 構成一個新字典 過濾字段:當前對象主鍵值
    params[filter_field] = pk
    # 利用urlencode將鍵值對轉化爲a=1&b=2的格式
    _url = params.urlencode()

    if int(cid) == pk:
        # get請求數據int轉換後與對象主鍵值匹配,匹配成功添加active類
        link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
    else:
        # print(obj)  # 蘋果出版社 香蕉出版社  alex  egon
        # print(type(obj))   # <class 'app01.models.Publish'>  <class 'app01.models.Author'>
        link_tag = "<a href='?%s'>%s</a>" % (_url, text)

  兩種data_list,一種是QuerySet,一種是數組套字典。兩種數據類型的處理方式略有不一樣。

  顯示效果:

  

  這樣作完後點擊TITLE下的過濾項是查不到任何對應數據的。這是由於默認傳遞的過濾字段都是PK值,可是針對普通字段過濾須要傳遞過濾字段值。

四、處理數據標籤時過濾字段按狀況拆分

# 處理數據標籤
for obj in data_list:   # obj是每個對象(或者是數組)
    """循環每個過濾字段關聯的數據"""
    if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
        # <QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>
        pk = obj.pk
        text = str(obj)
        params[filter_field] = pk   # 過濾字段:當前對象主鍵值
    else:
        # 列表裏面套着字典 data_list=[{"pk":1, "title":"go"},....]
        pk = obj.get("pk")
        text = obj.get(filter_field)
        params[filter_field] = text   # 過濾字段:當前對象字段值

    # 利用urlencode將鍵值對轉化爲a=1&b=2的格式
    _url = params.urlencode()

    if cid == str(pk) or cid == text:
        # get請求數據int轉換後與對象主鍵值匹配,匹配成功添加active類
        link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
    else:
        # print(obj)  # 蘋果出版社 香蕉出版社  alex  egon
        # print(type(obj))   # <class 'app01.models.Publish'>  <class 'app01.models.Author'>
        link_tag = "<a href='?%s'>%s</a>" % (_url, text)
        # print(link_tag)  # <a href=>蘋果出版社</a>

    temp.append(link_tag)

  注意:

(1)params分拆爲兩種狀況

  一開始統一用params[filter_field] = pk 來設置過濾字段,可是設置普經過濾字段後,若是title=7這樣是沒法進行過濾的,必須讓過濾字段等於"go"、"python"等字段值。所以將params也分拆爲兩種狀況:

if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
    # <QuerySet [<Publish: 蘋果出版社>, <Publish: 香蕉出版社>]>
    pk = obj.pk
    text = str(obj)
    params[filter_field] = pk   # 過濾字段:當前對象主鍵值
else:
    # 列表裏面套着字典 data_list=[{"pk":1, "title":"go"},....]
    pk = obj.get("pk")
    text = obj.get(filter_field)
    params[filter_field] = text   # 過濾字段:當前對象字段值

(2)cid(get請求數據)判斷的調整

  cid = self.request.GET.get(filter_field, 0) 因而可知cid是get請求傳遞的值,以前默認都是pk值,如今有多是pk值也多是"python"等普通字段。所以須要調整cid判斷:

 

if cid == str(pk) or cid == text:
    # get請求數據int轉換後與對象主鍵值匹配,匹配成功添加active類
    link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
else:
    # print(obj)  # 蘋果出版社 香蕉出版社  alex  egon
    # print(type(obj))   # <class 'app01.models.Publish'>  <class 'app01.models.Author'>
    link_tag = "<a href='?%s'>%s</a>" % (_url, text)
    # print(link_tag)  # <a href=>蘋果出版社</a>

temp.append(link_tag)

(3)最終展現效果

  

9、filter_list配置與否,決定是否顯示FILTER

  list_view.html:

<div class="col-md-3">
    {% if showlist.config.list_filter %}
        {# list_filter有值才顯示FILTER #}
        <div class="filter">
            <h4>Filter</h4>
            {% for filter_field, linktags in show_list.get_filter_linktags.items %}
                <div class="well">
                    {# upper方法改成大寫 #}
                    <p>{{ filter_field.upper }}</p>
                    {% for link in linktags %}
                        <p>{{ link|safe }}</p>
                    {% endfor %}
                </div>
            {% endfor %}
        </div>
    {% endif %}
</div>
相關文章
相關標籤/搜索