三、DRF的使用
1.DRF的Request和Response类
DRF对Django的Request和Response类进行了进一步的封装,因此使用起来更方便。
request.data返回请求正文的解析内容,代替了标准request.POST和request.FILES属性,具体如下:
它包括所有已解析的内容,包括文件和非文件输入;
它支持解析除以外的HTTP方法的内容POST,这意味着您可以访问PUT和PATCH请求的内容;
它支持REST框架的灵活请求解析,而不仅仅是支持表单数据。例如,可以以处理传入表单数据的相同方式处理传入JSON数据。
request.query_params代替了request.GET,有助于使代码库更加正确和明显,任何HTTP方法类型都可以包括查询参数,而不仅仅是GET请求。
request.parsers用于解析数据。DRF包括许多内置的Parser类,以保证可以接收各种媒体类型的请求并解析,包括JSONParser、FormParser、MultiPartParser等。还支持定义自己的自定义解析器,这使您可以灵活地设计API接受的媒体类型。
request.user通常会返回的实例django.contrib.auth.models.User,尽管其行为取决于所使用的身份验证策略。
DRF通过提供一个Response类来支持HTTP内容协商,该类允许您根据客户端请求返回可以呈现为多种内容类型的内容。
也可以根据需要从视图中返回常规HttpResponse或StreamingHttpResponse对象。使用Response类只是为返回内容协商的Web API响应提供了一个更好的接口,该响应可以呈现为多种格式。
2.DRF过滤器
DRF提供了过滤功能,来实现简单高效的过滤。
views.py如下:
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): '''商品列表页''' # queryset = Goods.objects.all() serializer_class = GoodsSerializer pagination_class = GoodsPagination def get_queryset(self): queryset = Goods.objects.all() price_min = self.request.query_params.get('price_min', default=0) if price_min: queryset = queryset.filter(shop_price__gt=int(price_min)) return queryset
显示:
显然,在传入price_min参数后,显示到前端的数据量也会发生变化。
但是这显得很麻烦,可以用更简单的方式实现,即使用django-filter实现,包括DjangoFilterBackend(与后台管理系统表现相同)、SearchFilter、OrderingFilter等,即字段过滤、搜索、排序3种方式。
过滤的使用
通过django-filters的DjangoFilterBackend类实现字段过滤。
先实现精确过滤,views.py如下:
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): '''商品列表页''' queryset = Goods.objects.all() serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = [DjangoFilterBackend] filterset_fields = ['name', 'market_price']
settings.py中进行配置:
# DRF配置 REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'] }
显示:
此时,可以根据字段进行过滤,但是只能精确比配,对于字符串型字段不能模糊匹配,对于数值型字段也不能匹配区间,因此需要自定义filters,新建filters.py如下:
import django_filters from .models import Goods class GoodsFilter(django_filters.rest_framework.FilterSet): '''商品过滤类''' name = django_filters.CharFilter(field_name="name", lookup_expr='contains') min_price = django_filters.NumberFilter(field_name="market_price", lookup_expr='gte') max_price = django_filters.NumberFilter(field_name="market_price", lookup_expr='lte') class Meta: model = Goods fields = ['name', 'min_price', 'max_price']
vies.py修改如下:
from rest_framework import mixins, viewsets from rest_framework.pagination import PageNumberPagination from django_filters.rest_framework import DjangoFilterBackend from .models import Goods from .serializers import GoodsSerializer from .filters import GoodsFilter # Create your views here. class GoodsPagination(PageNumberPagination): page_size = 10 page_size_query_param = 'page_size' page_query_param = 'p' max_page_size = 100 class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): '''商品列表页''' queryset = Goods.objects.all() serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = [DjangoFilterBackend] filter_class = GoodsFilter
显示:
此时可以进行更加个性化的过滤。
除此之外,还可以自定义过滤的方法来满足个性化的需求。
搜索的使用
DRF的SearchFilter类基于Django-admin的搜索功能,支持简单的基于单个查询参数的搜索。
views.py如下:
from rest_framework import mixins, viewsets, filters from rest_framework.pagination import PageNumberPagination from django_filters.rest_framework import DjangoFilterBackend from .models import Goods from .serializers import GoodsSerializer from .filters import GoodsFilter # Create your views here. class GoodsPagination(PageNumberPagination): page_size = 10 page_size_query_param = 'page_size' page_query_param = 'p' max_page_size = 100 class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): '''商品列表页''' queryset = Goods.objects.all() serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = [DjangoFilterBackend, filters.SearchFilter] filter_class = GoodsFilter search_fields = ['name', 'goods_brief', 'goods_desc']
显示:
显然,实现了搜索,在给定的字段中搜索,匹配到关键字则展示到前台。
还可以通过在字段前面加上各种字符来限制搜索行为search_fields:
- '^'开始搜索
- '='完全匹配
- '@'全文搜索(当前仅支持Django的MySQL后端)
- '$'正则表达式搜索
如修改如下:
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): '''商品列表页''' queryset = Goods.objects.all() serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = [DjangoFilterBackend, filters.SearchFilter] filter_class = GoodsFilter search_fields = ['=name', 'goods_brief', 'goods_desc']
显示:
显然,字符限制只是对指定的字段起作用,其他字段并不受影响,可以根据需要选择。
排序的使用
一般需要对商品根据销量、价格等排序,通常使用DRF的OrderingFilter类,它支持简单的查询参数控制的结果排序。
在views.py中增加属性:
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): '''商品列表页,并实现分页、搜索、过滤、排序''' queryset = Goods.objects.all() serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filter_class = GoodsFilter search_fields = ['name', 'goods_brief', 'goods_desc'] ordering_fields = ['sold_num', 'market_price']
显示:
此时实现了按照指定字段进行排序。