Django過濾和分頁
場景描述
在編寫WEB應用時,會通過類似www.example.com/books/
的URL查詢書本列表。如果要查詢作者John的書籍呢,只要在URL後加過濾參數就好,www.example.com/books/?author=John
。
下面我們來看看Django的實現:
定義一個書本的模型,包含書本名、作者和價格。在後臺不指定條件的情況下,返回所有的書籍,指定作者名,就返回該作者名下的書籍。
# models.py
class Book(models.Model):
name = models.CharField('名稱', max_length=128)
author = models.CharField('作者', max_length=32)
price = models.DecimalField('價格', decimal_places=2, max_digits=7)
created_date = models.DateTimeField('添加時間', auto_now_add=True)
# views.py
from .models import Book
import json
import decimal
from datetime import datetime
from django.http import HttpResponse
class CustomEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
if isinstance(o, datetime):
return o.strftime('%Y-%m-%d %H:%M:%S')
def get_books(request):
author = request.GET.get('author', '')
if author:
books = Book.objects.filter(author=author).values('name', 'author', 'price', 'created_date')
else:
books = Book.objects.all().values('name', 'author', 'price', 'created_date')
ret = {
"total": books.count(),
"data": list(books)
}
ret = json.dumps(ret, cls=CustomEncoder)
return HttpResponse(ret)
#urls.py
from goods import views as goods_view
urlpatterns = [
url('^books/', goods_view.get_books)
]
現在讓我們通過瀏覽器查看效果:
在瀏覽器輸入127.0.0.1:8000/books/
返回的是提前在數據庫內存儲的四條記錄,加了過濾參數author
,返回的是作者John名下的兩本書籍,是不是很簡單呢。
多個參數查詢
前面過濾只有一個author字段,如果有四五個參數呢,代碼就會像下面一樣。雖然可以實現需要的功能,但是重複的代碼比較多,使用django-filter
就可以簡化這些操作。
def get_books(request):
author = request.GET.get('author', '')
created_date__gt = request.GET.get('created_date__gt', '')
name = request.GET.get('name', '')
books = Book.objects.all().values('name', 'author', 'price', 'created_date')
if author:
books = books.filter(author=author)
if created_date__gt:
books = books.filter(created_date__gt=created_date__gt)
if name:
books = books.filter(name=name)
ret = {
"total": books.count(),
"data": list(books)
}
ret = json.dumps(ret, cls=CustomEncoder)
return HttpResponse(ret)
django-filter介紹
Django-filter is a generic, reusable application to alleviate writing some of the more mundane bits of view code. Specifically, it allows users to filter down a queryset based on a model’s fields, displaying the form to let them do this.
django-filter
一般與django的第三方框架restful framework
組合使用, 我也是在使用
restful的時候,纔想到能不能單獨拿出來使用。詳細瞭解可以查詢官方文檔
下面是演示代碼,CustomFilter
繼承FilterSet
,使用方式類似於Django的ModelForm,在Meta中指定模型,fields則指定過濾的條件。exact
指明字段相等,lt
,gt
則會與字段名組合成created_date__gt
和created_date__lt
在filter()中使用,是不是很方便。django-filter其它功能和使用方式,在這裏就不詳細敘述了,感興趣的同學自己探索使用吧。
import django_filters
class CustomFilter(django_filters.FilterSet):
class Meta:
model = Book
fields = {
'name': ['exact'],
'created_date': ['lt', 'gt', 'year'],
'author': ['exact'],
'price': ['lt', 'gt']
}
def get_books(request):
books = Book.objects.all().values('name', 'author', 'price', 'created_date')
f = CustomFilter(request.GET, queryset=books)
ret = {
"total": f.qs.count(),
"data": list(f.qs)
}
ret = json.dumps(ret, cls=CustomEncoder)
return HttpResponse(ret)