iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 15
0
Modern Web

加速你的 Django 網站開發 - Django 的好用套件系列 第 15

15. django-url-filter

一般在製作列表類的網頁時,常常最讓人困擾的就是篩選、排序跟自定輸出欄位。

那也很常看到這些處理方法:

  • 一次取得所有資料,在網頁裡撰寫 JavaScript ,在瀏覽器端做篩選、排序跟自定欄位的工作。
  • 透過參數方式,告知網站該做的事情,然後重新取得結果。

第一個方式,問題是在網站端,「一次取得所有資料」會影響網站回應的速度。網站首先要去資料庫查詢,然後再把資料轉換為 JSON 回應給客戶端,如果沒有使用快取,那麼每次都會要從資料庫拿一次資料,再傳輸這麼多資料給客戶端。

第二個方式,問題在於回應會稍慢,因為每次變更條件,就會要告知網站,網站再次依據條件來查詢、回應。但是好處在於,回應的資料不會像前者那麼的多。

django-url-filter 主要是讓開發者在使用第二種方式時,能夠比較輕鬆。它把 filter 的處理機制標準化,讓開發者能夠簡便的做出篩選功能。它更棒的是,同時支援了 Django 的 class based view 跟 REST framework 的 APIView,接下來就讓我們看怎麼使用吧。

專案網址:https://github.com/miki725/django-url-filter

安裝

poetry add django-url-filter

使用

django-url-filter 可以應用在 Django class based view 與 REST framework 的 ListAPI 上,下面我們就先介紹在 Django class based view 裡怎麼使用。

Django Class based view

Django class based view 在取得資料時,都要填寫 queryset 屬性,實際上的運作,是因為 ListView/DetailView 所繼承的 MultipleObjectMixin/SingleObjectMixin 類別會透過 get_queryset() 來進行查詢,而 get_queryset() 會先讀取 queryset 屬性,如果沒有,預設使用 model 屬性的 objects 來當做 queryset,也就是 model.objects 。

所以在傳遞參數做篩選時,都會 override get_queryset() 來處理。

django-url-filter 也是如此,首先先繼承 ModelFilterSet ,然後指定 Meta ,聲明要用哪個 model 以及允許的欄位。

# views
from django.views.generic import ListView
from url_filter.filtersets import ModelFilterSet
from .models import Article

class ArticleFilterSet(ModelFilterSet):
    class Meta(object):
        model = Article
        fields = ['title', 'reporter', 'content']

class ArticleListView(ListView):
    """ListView for MedicalPersonnel."""

    model = Article
    template_name = "news/article_list.html"
    paginate_by = 10
    ordering = 'id'

    def get_queryset(self):
        """Return custom queryset."""
        queryset = super().get_queryset()
        return ArticleFilterSet(
                data=self.request.GET, queryset=queryset).filter()

這裡我們建立 ArticleFilterSet 去繼承 ModelFilterSet,然後聲明是 Article 這個 model,並允許使用 title, reporter, content 來篩選。

ArticleListView 是處理 Article 列表的 View,它繼承了 ListView,然後告知要處理的 model,接著就在 get_queryset() 裡處理參數。這裡把 request.GET (也就是 Query parameter) 傳入 ArticleFilterSet 的初始函數裡,ArticleFilterSet 會解析 request.GET,然後進行轉換,呼叫 filter() 以後,就可以得到查詢結果。

接著來試試看,打開瀏覽器在網址列輸入:http://localhost:8000/article/?title__icontains=foo

就可以看到結果啦

REST framework

django-url-filter 也可以搭配 REST framework 使用。

from rest_framework.generics import ListAPIView
from url_filter.integrations.drf import DjangoFilterBackend
from .models import Article
from .serializers import ArticleSerializer  # REST framework (1) 時定義的

class ArticleFilterSet(ModelFilterSet):
    class Meta(object):
        model = Article
        fields = ['title', 'reporter', 'content']

class ArticleListAPIView(ListAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    filter_backends = [DjangoFilterBackend]
    filter_class = ArticleFilterSet

一樣沿用前個例子的 ArticleFilterSet,然後撰寫 ArticleListAPIView ,繼承自 ListAPIView。

填寫 filter_backends 跟 filter_class,filter_backends 固定填寫 django-url-filter 所提供的 DjangoFilterBackend,這個 backend 會讀取 filter_class 這個屬性所指定的 FilterSet,那麼在 API 被呼叫、進行查詢時,就會使用 ArticleFilterSet 來讀取參數進行篩選。

其他

django-url-filter 也可以應用在 SQLAlchemy 上,也就是說 flask 也可以使用。

結語

django-url-filter 讓我們可以使用統一的方式來進行篩選,真的是很方便。


上一篇
14. django-anymail
下一篇
16. djangorestframework-firebase
系列文
加速你的 Django 網站開發 - Django 的好用套件30

尚未有邦友留言

立即登入留言