Django restframework加Vue打造前后端分离的网站(九)查询筛选和搜索
在前面讲后端API的文章中,已经有介绍怎么创建出get / post / put / patch / delete的方法,对应着model中的业务对象。不过在开发过程中,这些API是不够的,往往需要特定的查询、业务性质的筛选、以及搜索。
比如有一个电商网站,可以列举出所有的电脑,也可以进入某一个电脑的配置页面,在用户使用时,还需要查询在最近一年发布的产品的数量,筛选属于平板电脑的产品,搜索某一个型号的电脑,等等。在这篇文章中,会以简单的例子记录如何查询筛选搜索。
比如现在有一个computer的model
class Computer(models.Model):
COMPUTER_TYPES = (
("laptop", "laptop"),
("tablet", "tablet"),
("desktop", "desktop")
)
name = models.CharField(max_length=100)
computer_type = models.CharField(choices=COMPUTER_TYPES, default=COMPUTER_TYPES[0][0], max_length=100)
cpu = models.CharField(max_length=100)
memory = models.CharField(max_length=100)
disk = models.CharField(max_length=100)
main_board = models.CharField(max_length=100)
display_card = models.CharField(max_length=100)
monitor = models.CharField(max_length=100)
publish_time = models.DateTimeField(default=timezone.now)
halt_time = models.DateTimeField(blank=True)
查询
前端需要显示当前网站里售卖的电脑一共有多少,于是在view.py中新增一个查询,继承APIView(可以参考前面的文章:Django restframework加Vue打造前后端分离的网站(三)在View中自定义API)
from .models import Computer
class ComputerAmount(APIView):
def get(self, request):
"""
Return amount of all computers.
"""
count = {"count": Computer.objects.count()}
return Response(count)
在url.py中新增路由
from django.urls import path
from . import views
urlpatterns = [
path('', views.ComputerList.as_view(), name='computer_list'),
path(r'<int:pk>/', views.ComputerDetail.as_view(), name='computer_detail'),
path(r'amount/', views.ComputerAmount.as_view(), name='computer_amount'),
]
此时get请求类似http://127.0.0.1:8000/automation/api/computer/amount的地址即可获取到需要的数据。
筛选
根据条件筛选往往有两种,一种是在get请求中给予筛选的字段{"type_name": "tablet"},url仍然是原url;一种是筛选的字段体现在url中,比如http://127.0.0.1:8000/automation/api/computer/tablet/. 两者只是在取参数不一致,其他几乎一样。如果继承于generics.ListAPIView则重写.get_queryset(),如果继承于APIView,则重写.get().
在view.py中新增
from .models import Computer
from .serializers import ComputerSerializer
from rest_framework import generics
class ComputerFilterInUrl(generics.ListAPIView):
serializer_class = ComputerSerializer
def get_queryset(self):
"""
This view return all computers based on url parameter
"""
type_name = self.kwargs['type_name']
return Computer.objects.filter(computer_type=type_name)
class ComputerFilterInRequest(generics.ListAPIView):
serializer_class = ComputerSerializer
def get_queryset(self):
"""
This view return all computers based on request parameter
"""
return Computer.objects.filter(computer_type=self.request.data["type_name"])
在url.py中对这两个class新增路由
from django.urls import path
from . import views
urlpatterns = [
...
path(r'in_url/<str:type_name>/', views.ComputerFilterInUrl.as_view(), name='computer_filter_in_url'),
path(r'in_request/', views.ComputerFilterInRequest.as_view(), name='computer_filter_in_request'),
]
搜索
其实搜索也是一种筛选,只是在restframework中使用方式略有不同,便分开介绍。
简单来说,在继承于generics.ListAPIView的class中声明filter_backends和search_fields即可使用。
from .models import Computer
from .serializers import ComputerSerializer
from rest_framework import generics
from rest_framework import filters
class ComputerList(generics.ListAPIView):
"""
get:
Return all projects or based on search condition.
"""
queryset = Computer.objects.all().order_by("id")
serializer_class = ComputerSerializer
filter_backends = [filters.SearchFilter]
search_fields = ["name", "=computer_type"]
搜索可以部分匹配,也可以完全匹配,也可以正则匹配,官方文档是这么说的:
- '^' Starts-with search.
- '=' Exact matches.
- '@' Full-text search. (Currently only supported Django's MySQL backend.)
- '$' Regex search
上面的搜索则代表name可以部分匹配,但是搜索computer_type时则是必须完全匹配才行。比如http://127.0.0.1:8000/automation/api/computer/?search=apple则是名字里有apple都会筛选出来,http://127.0.0.1:8000/automation/api/computer/?computer_type=tabl则是computer_type是tabl才给出结果,当然这里没有写全就不会有结果返回。
另外默认的搜索参数名是search,想自定义的话则在settings.py中注明,比如
# in settings.py
REST_FRAMEWORK = {
...
'SEARCH_PARAM': 's'
}
此时生效的搜索链接则是http://127.0.0.1:8000/automation/api/computer/?s=apple