【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

ListModelMixinlist 方法实现了分页和序列化,视图继承它可以省略自己实现分页和序列化。

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 过滤

drffilter 用法: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&

原文地址:https://www.cnblogs.com/midworld/p/13629680.html