【Vue+DRF 生鲜电商】商品列表页(三)
1. APIView 实现商品列表页
安装依赖:
pip install coreapi # drf的文档支持
pip install django-guardian # drf对象级别的权限支持
1、MxShop/urls.py
:
from django.urls import path, include, re_path
from django.views.static import serve
from rest_framework.documentation import include_docs_urls
urlpatterns = [
# path('admin/', admin.site.urls),
path('xadmin/', xadmin.site.urls),
path('ueditor/', include('DjangoUeditor.urls')),
path('media/<path:path>', serve, {'document_root': MEDIA_ROOT}),
# drf 文档
path('docs', include_docs_urls(title='hubery')),
path('api-auth/', include('rest_framework.urls')),
]
2、新建 goods/serializers.py
,序列化商品数据:
from rest_framework import serializers
class GoodsSerializer(serializers.Serializer):
"""
商品
"""
name = serializers.CharField(required=True, max_length=100)
click_num = serializers.IntegerField(default=0)
goods_front_image = serializers.ImageField()
# 也可以使用
# class CategorySerializer(serializers.ModelSerializer):
# """
# 分类
# """
# class Meta:
# model = GoodsCategory # 指定模型
# fields = '__all__' # 所以字段
serializers.ModelSerializer
类似于 Django ModelForm
可以指定模型。
2、goods/views.py
:
from rest_framework.response import Response
from rest_framework.views import APIView
class GoodsListView(APIView):
"""
商品列表
"""
def get(self, request, format=None):
goods = Goods.objects.all()
goods_serilizer = GoodsSerializer(goods, many=True)
return Response(goods_serilizer.data)
APIView
需要自己实现 get、post
方法来处理请求。
3、MxShop/urls.py
配置商品列表路由:
from django.urls import path, include, re_path
from django.views.static import serve
from goods.views import GoodsListView
urlpatterns = [
path('goods/', GoodsListView.as_view(), name='goods'),
]
运行项目,访问:http://127.0.0.1:8000/goods
查看商品列表页数据。
1.1 处理外键字段
通过上述方式处理,查询到的商品数据,分类 category
外键字段的数据是商品类别表的字段 ID
,若想能够全部显示相关分类的所有信息,需要重写方法,覆盖对应的外键字段:
1、goods/serializers.py
:
from rest_framework import serializers
from goods.models import Goods, GoodsCategory
class CategorySerializer(serializers.ModelSerializer):
"""
分类
"""
class Meta:
model = GoodsCategory
fields = '__all__'
class GoodsSerializer(serializers.ModelSerializer):
"""
商品
"""
# 覆盖外键字段 category
category = CategorySerializer()
class Meta:
model = Goods
fields = '__all__'
2. GenericView 实现商品列表页
GenericView
继承 APIView
,比 APIView
功能更强大, 使用的时候需要指定:queryset、serializer_class
。
ListModelMixin
中 list
方法实现了分页和序列化,视图继承它可以省略自己实现分页和序列化。
ListModelMixin
源码:
class ListModelMixin:
"""
List a queryset. # 列出查询集
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
goods/views.py
:
from rest_framework import mixins, viewsets
from rest_framework import generics
from goods.serializers import GoodsSerializer
from .models import Goods
class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
"""
商品列表
"""
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
3. 分页
3.1 全局分页
配置全局分页只需配置 MxShop/Settings.py
即可:
REST_FRAMEWORK = {
#分页
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
#每页显示的个数
'PAGE_SIZE': 10,
}
3.2 自定义分页
自定义分页需要重写分页类,继承 PageNumberPagination
,可以自定义:
- 每页条数
- 最大页数
- 获取页码的参数等
goods/views.py
:
from rest_framework.pagination import PageNumberPagination
from rest_framework import mixins, viewsets
from rest_framework import generics
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from goods.filters import GoodsFilter
from goods.serializers import GoodsSerializer
from .models import Goods
class GoodsPagination(PageNumberPagination):
"""
自定义商品列表分页
"""
page_size = 10 # 每页显示个数
page_size_query_param = 'page_size' # 可以动态改变每页显示的个数
page_query_param = 'page' # 页码参数
max_page_size = 100 # 最多能显示多少页
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
商品列表页
"""
# 分页
pagination_class = GoodsPagination
# 这里必须要定义一个默认的排序,否则会报错
queryset = Goods.objects.all().order_by('id')
serializer_class = GoodsSerializer
使用:http://127.0.0.1:8000/goods/?page=2&page_size=20
注意:将全局分页功能注释
4. viewsets 和 router 配置商品列表路由
1、MxShop/urls.py
:
from django.urls import path, include, re_path
from django.views.static import serve
from rest_framework.documentation import include_docs_urls
from rest_framework.routers import DefaultRouter
import xadmin
from MxShop.settings import MEDIA_ROOT
from goods.views import GoodsListViewSet
router = DefaultRouter()
router.register(r'goods', GoodsListViewSet, basename='goods')
urlpatterns = [
# path('admin/', admin.site.urls),
path('xadmin/', xadmin.site.urls),
path('ueditor/', include('DjangoUeditor.urls')),
path('media/<path:path>', serve, {'document_root': MEDIA_ROOT}),
# drf 文档
path('docs', include_docs_urls(title='hubery')),
path('api-auth/', include('rest_framework.urls')),
# 商品
# path('goods/', GoodsListView.as_view(), name='goods-list'),
re_path('^', include(router.urls)),
]
2、goods/views.py
:
queryset
要定义一个默认的排序,否则会报错:
from rest_framework.pagination import PageNumberPagination
from rest_framework import mixins, viewsets
from rest_framework import generics
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from goods.filters import GoodsFilter
from goods.serializers import GoodsSerializer
from .models import Goods
class GoodsPagination(PageNumberPagination):
"""
自定义商品列表分页
"""
page_size = 10 # 每页显示个数
page_size_query_param = 'page_size' # 可以动态改变每页显示的个数
page_query_param = 'page' # 页码参数
max_page_size = 100 # 最多能显示多少页
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
商品列表页
"""
# 分页
pagination_class = GoodsPagination
# 这里必须要定义一个默认的排序,否则会报错
queryset = Goods.objects.all().order_by('id')
serializer_class = GoodsSerializer
5. 商品过滤和搜索
5.1 过滤
drf
的 filter
用法:http://www.django-rest-framework.org/api-guide/filtering/
1、MxShop/settings.py
:
INSTALLED_APPS = [
'django_filters',
]
2、新建 goods/filters.py
用于过滤:
import django_filters
from .models import Goods
class GoodsFilter(django_filters.rest_framework.FilterSet):
"""
商品过滤
"""
# field_name 为要过滤的字段,lte 为执行的行为,这里为小于等于本店价格
price_min = django_filters.NumberFilter(field_name='shop_price', lookup_expr='gte')
price_max = django_filters.NumberFilter(field_name='shop_price', lookup_expr='lte')
class Meta:
model = Goods
fields = ['price_min', 'price_max']
在这里对商品进行过滤,查找 [price_min, price_max]
范围的商品。
3、goods/views.py
:
from django_filters.rest_framework import DjangoFilterBackend
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
商品列表页
"""
# 分页
pagination_class = GoodsPagination
# 这里必须要定义一个默认的排序,否则会报错
queryset = Goods.objects.all().order_by('id')
serializer_class = GoodsSerializer
# 过滤
filter_backends = (DjangoFilterBackend, )
# 设置 filter 的类为自定义的类
filter_class = GoodsFilter
使用:http://127.0.0.1:8000/goods/?price_min=20&price_max=30
5.2 搜索
goods/views.py
:
from django_filters.rest_framework import DjangoFilterBackend
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
商品列表页
"""
# 分页
pagination_class = GoodsPagination
# 这里必须要定义一个默认的排序,否则会报错
queryset = Goods.objects.all().order_by('id')
serializer_class = GoodsSerializer
# 过滤
filter_backends = (DjangoFilterBackend, filters.SearchFilter,)
# 设置 filter 的类为自定义的类
filter_class = GoodsFilter
# 搜索,=name 为精确搜索,也可以使用正则
search_fields = ('=name', 'goods_brief')
使用:http://127.0.0.1:8000/goods/?search=水果
5.3 排序
goods/views.py
:
from django_filters.rest_framework import DjangoFilterBackend
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
商品列表页
"""
# 分页
pagination_class = GoodsPagination
# 这里必须要定义一个默认的排序,否则会报错
queryset = Goods.objects.all().order_by('id')
serializer_class = GoodsSerializer
# 过滤
filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
# 设置 filter 的类为自定义的类
filter_class = GoodsFilter
# 搜索,=name 为精确搜索,也可以使用正则
search_fields = ('=name', 'goods_brief')
# 排序
ordering_fields = ('sold_num', 'add_time')
使用:http://127.0.0.1:8000/goods/?ordering=sold_num&