Vue+Django REST framework实战
搭建一个前后端分离的生鲜超市网站
Django rtf 完成 商品列表页下
drf对于django的request和response进行了一层封装。
浏览器请求的request会被drf进行一定的封装,扩展了标准的http request
REST framework's Request class extends the standard HttpRequest, adding support for REST framework's flexible request parsing and request authentication
在基本的httpRequest上进行了扩展。增加了对REST框架灵活的请求解析和请求认证的支持。
Request parsing 对于用户发过来的数据进行一定的解析
.query_params
里面放着get请求传递过来的参数?min=10
.parsers
用户传递过来的数据有很多种类型。比如file啊。post过来的json啊。字符串。
使用drf给我们提供的各种parsers
什么类型的数据都可以接收、调用parser指定对应的解析器
Authentication
认证中的.user就能获取到当前的用户。.auth返回一些额外的信息
比如前台要求返回json 就返回json。 要求返回浏览器可以解析的html就返回html
response也是支持template_render的返回html
通过drf为我们提供的过滤功能简单快速的完成过滤
GenericViewSet继承的GenericAPIView中有一个可以供我们重写的方法用于我们的过滤
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
商品列表页
"""
# queryset是一个属性
# good_viewset.queryset就可以访问到
# 函数就必须调用good_viewset.get_queryset()函数
# 如果有了下面的get_queryset。那么上面的这个就不需要了。
# queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
queryset = Goods.objects.all()
def get_queryset(self):
# 价格大于100的
price_min = self.request.query_params.get('price_min', 0)
if price_min:
self.queryset = Goods.objects.filter(shop_price__gt=price_min)
return self.queryset
老师使用的drf中的这里将queryset 放在get 函数内部返回即可。
经我测试,新版本必须如上面代码所示
可能的报错:
assert queryset is not None, '`base_name` argument not specified, and could ' \
AssertionError: `base_name` argument not specified, and could not automatically determine the name from the viewset, as it does not have a `.queryset` attribute.
可以说报错信息写的很明显了。我们缺少一个queryset的属性。
可能的警告:
UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: QuerySet.
paginator = self.django_paginator_class(queryset, page_size)
这个是因为我们没有为我们的返回数据添加一个指定的排序方式。
self.queryset = Goods.objects.filter(shop_price__gt=price_min).order_by('-add_time')
添加指定的排序方式消除警告。
访问: http://127.0.0.1:8000/goods/?page=2&price_min=100
可以看到过滤效果
即使这样我们还是觉得这个过滤实在是太麻烦了。
又要获取参数,又要判断参数是否存在,存在之后转化为int(我没转)
虽然现在看起来代码不多,但是如果有很多的过滤参数,那么过滤这件事将会变得较为复杂。
使用drf 的 filter
http://www.django-rest-framework.org/api-guide/filtering/
传统的filter 跟我们在xadmin后台中的过滤器差不多。
列表页常见的三种过滤,就是列表页的传统字段精确过滤,搜索过滤,以及排序。
DjangoFilterBackend
pip install django-filter
django_filters,
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
goods/views.py
from django_filters.rest_framework import DjangoFilterBackend
官方示例:
class UserListView(generics.ListAPIView):
...
filter_backends = (DjangoFilterBackend,)
我们需要在我们的view中设置
filter_backends = (DjangoFilterBackend,)
我们既然决定使用djangofilter那么就可以不用get_queryset方法了。注释掉
官方示例:
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = ('category', 'in_stock')
我们的实践:
# 设置我们需要进行过滤的字段
filter_fields = ('name', 'shop_price')
可以看到我们页面的右上多了一个过滤器。这是一个精确地等于的过滤器
?name=&shop_price=100
https://django-filter.readthedocs.io/en/master/
他不但是一个满足drf的filter 也是用于
filter_class
我们可以自定义我们自己的filter类,进行自定义的filter类
在goods目录下新建filters.py
# -*- coding:utf-8 _*-
__author__ = 'mtianyan'
__date__ = '2018/03/03 00:44'
from django_filters import rest_framework as filters
from goods.models import Goods
class GoodsFilter(filters.FilterSet):
"""
商品的过滤类
"""
# 指定字段以及字段上的行为,在shop_price上大于等于
price_min = filters.NumberFilter(name="shop_price", lookup_expr='gte')
price_max = filters.NumberFilter(name="shop_price", lookup_expr='lte')
class Meta:
model = Goods
fields = ['price_min', 'price_max']
# 设置三大常用过滤器之DjangoFilterBackend
filter_backends = (DjangoFilterBackend,)
# 设置filter的类为我们自定义的类
filter_class = GoodsFilter
注释掉: filter_fields,这时候我们的filter_fields已经失效了
过滤器没有确定的按钮是因为继承错了。应该继承rf的
import rest_framework as filters
我们不一定在这个类里面使用它自带的过滤方法。还可以自定义我们的过滤方法,这个在后面会讲到。
https://code.ziqiangxuetang.com/django/django-queryset-api.html
Django QuerySetAPI
模糊查询
# 行为: 名称中包含某字符,且字符不区分大小写
name = filters.CharFilter(name="name", lookup_expr="icontains")
class Meta:
model = Goods
fields = ['price_min', 'price_max', 'name']
配置drf里面的SearchFilter
http://www.django-rest-framework.org/api-guide/filtering/#searchfilter
from rest_framework import filters
# 设置三大常用过滤器之DjangoFilterBackend, SearchFilter
filter_backends = (DjangoFilterBackend, filters.SearchFilter)
上面代码中的filter一定要注意不是django中的filter而是restframe中的。不然会报错。
filter_backends = (DjangoFilterBackend, filters.SearchFilter)
AttributeError: module 'django_filters.rest_framework.filters' has no attribute 'SearchFilter'
配置了search_fields之后配置我们的search_fields
# 设置我们的search字段
search_fields = ('name', 'goods_brief', 'goods_desc')
search_fields.
^
Starts-with search.=
Exact matches.@
Full-text search. (Currently only supported Django's MySQL backend.)$
Regex search.以当前字段值开头的,等于类似于字段精确过滤。全文搜索。正则表达式搜索
search_fields = ('=username', '=email')
By default, the search parameter is named 'search', but this may be overridden with the SEARCH_PARAM setting.
默认的search参数为
search。可以在设置中覆盖SEARCH_PARAM
进行自定义。
可以为多个字段配置不同精度的搜索。比如name是精确搜索,简介是模糊搜索这种。
OrderingFilter支持排序
# 设置三大常用过滤器之DjangoFilterBackend, SearchFilter
filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
# 设置排序
ordering_fields = ('sold_num', 'add_time')
一般全文搜索,真正的模糊查询是使用elasticSearch来做的。
but this may by overridden with the ORDERING_PARAM
setting.
重写order 参数。来实现url中指定参数值
不止数据的获取,数据的提交以及后面的login验证等,都可以在这个界面进行操作。