zoukankan      html  css  js  c++  java
  • (项目)生鲜超市(四)

    五、商品列表页面

    1、Django的view实现商品列表页面

      为了区分django的view和django rest framework的view,在goods下面新建view_base.py文件,该项目采用前后端分离,所以和模板技术不一样返回的是模本文件,现在给前端返回的必须是json数据:

    import json
    
    from django.views.generic import View
    from django.http import HttpResponse
    
    from goods.models import Goods
    
    
    class GoodsListView(View):
        """商品列表页"""
        def get(self, request):
            json_list = []
            # 获取所有的商品
            all_goods = Goods.objects.all()
    
            for good in all_goods:
                json_dict = {}
                # 将商品信息一字典的形式存储,然后添加到json_list中
                json_dict['name'] = good.name
                json_dict['category'] = good.category.name
                json_dict['market_price'] = good.market_price
                json_list.append(json_dict)
    
            # 返回json数据
            return HttpResponse(json.dumps(json_list), content_type='application/json')

      配置url:

    1 urlpatterns = [
    2     path('goods/', GoodsListView.as_view(), name='goods-list'),  # 商品列表页面
    3 ]

      现在访问http://127.0.0.1:8000/goods/即可看到返回的数据:

      当数据的字段比较多时,一个字段一个字段的提取很麻烦,可以用model_to_dict方法,将model整个转化为dict:

     1 import json
     2 
     3 from django.views.generic import View
     4 from django.http import HttpResponse
     5 from django.forms.models import model_to_dict
     6 
     7 from goods.models import Goods
     8 
     9 
    10 class GoodsListView(View):
    11     """商品列表页"""
    12     def get(self, request):
    13         json_list = []
    14         # 获取所有的商品
    15         all_goods = Goods.objects.all()
    16 
    17         # for good in all_goods:
    18         #     json_dict = {}
    19         #     # 将商品信息一字典的形式存储,然后添加到json_list中
    20         #     json_dict['name'] = good.name
    21         #     json_dict['category'] = good.category.name
    22         #     json_dict['market_price'] = good.market_price
    23         #     json_list.append(json_dict)
    24 
    25         for good in all_goods:
    26             json_dict = model_to_dict(good)
    27             json_list.append(json_dict)
    28 
    29         # 返回json数据
    30         return HttpResponse(json.dumps(json_list), content_type='application/json')

      现在去访问http://127.0.0.1:8000/goods/会出现问题,ImageFieldFile和add_time字段不能序列化:

      那么如何才能将所有的字段序列化呢?现在就可以用到django的serializers来序列化:

     1 import json
     2 
     3 from django.views.generic import View
     4 from django.http import HttpResponse, JsonResponse
     5 from django.forms.models import model_to_dict
     6 from django.core import serializers
     7 
     8 from goods.models import Goods
     9 
    10 
    11 class GoodsListView(View):
    12     """商品列表页"""
    13     def get(self, request):
    14         json_list = []
    15         # 获取所有的商品
    16         all_goods = Goods.objects.all()
    17 
    18         # for good in all_goods:
    19         #     json_dict = {}
    20         #     # 将商品信息一字典的形式存储,然后添加到json_list中
    21         #     json_dict['name'] = good.name
    22         #     json_dict['category'] = good.category.name
    23         #     json_dict['market_price'] = good.market_price
    24         #     json_list.append(json_dict)
    25 
    26         # for good in all_goods:
    27         #     json_dict = model_to_dict(good)
    28         #     json_list.append(json_dict)
    29         #
    30         # # 返回json数据
    31         # return HttpResponse(json.dumps(json_list), content_type='application/json')
    32 
    33         json_data = serializers.serialize('json', all_goods)
    34         json_data = json.loads(json_data)
    35         return JsonResponse(json_data, safe=False)

      现在访问http://127.0.0.1:8000/goods/即可看到已经将model中的所有字段序列化:

      django的serializers虽然可以很简单的将所有字段序列化,但是缺点也很明显:

    • 字段是定死的,不能灵活去序列化指定的字段
    • 从上面的截图可以看出,图片保存的是相对地址,还需要手动补全路径

      那么如何避免这些问题呢,现在就开始进行django rest framework的使用了。

    2、drf的APIview实现商品列表页面

      首先在虚拟环境中安装两个包:

    • pip install coreapi(drf的文档支持)
    • pip install django-guardian(drf对象级别的权限支持)

      然后配置drf文档的url:

    1 from rest_framework.documentation import include_docs_urls
    2 
    3 urlpatterns = [
    4     path('docs',include_docs_urls(title='倍思乐接口文档')),
    5 ]

      之前在settings.py中的INSTALLED_APPS中已经注册过rest_framework,如果没有注册,一定要注册进去。

      然后配置rest_framework的url:

    1 urlpatterns = [
    2     path('api-auth/',include('rest_framework.urls')),
    3 ]

      现在使用drf的序列化来实现商品列表页,在goods下新建serializers.py文件:

    1 from rest_framework import serializers
    2 
    3 
    4 class GoodsSerializer(serializers.Serializer):
    5     name = serializers.CharField(required=True, max_length=100)
    6     click_num = serializers.IntegerField(default=0)
    7     goods_front_image = serializers.ImageField()

      然后在goods/views.py中编写商品列表页面的接口:

     1 from django.shortcuts import render
     2 from rest_framework.views import APIView
     3 from rest_framework.response import Response
     4 
     5 from .models import Goods
     6 from .serializers import GoodsSerializer
     7 
     8 # Create your views here.
     9 
    10 
    11 class GoodsListView(APIView):
    12     """商品列表页"""
    13 
    14     def get(self, request, format=None):
    15         # 获取所有商品
    16         goods = Goods.objects.all()
    17 
    18         # 序列化
    19         goods_serializer = GoodsSerializer(goods, many=True)
    20 
    21         return Response(goods_serializer.data)

      注意要修改之前的url。然后访问http://127.0.0.1:8000/goods/:

      还可以通过Modelserializer来进行序列化,上面是通过Serializer来实现的,需要自己手动去添加序列化的字段,现在使用Modelserializer会更加方便,直接用__all__就可以将字段全部序列化:

     1 from rest_framework import serializers
     2 
     3 from .models import Goods
     4 
     5 
     6 # class GoodsSerializer(serializers.Serializer):
     7 #     name = serializers.CharField(required=True, max_length=100)
     8 #     click_num = serializers.IntegerField(default=0)
     9 #     goods_front_image = serializers.ImageField()
    10 
    11 
    12 class GoodsSerializer(serializers.ModelSerializer):
    13     class Meta:
    14         model = Goods
    15         fields = '__all__'

      上面的截图可以看出,category只显示了id,Serializer还可以嵌套去使用,覆盖外键字段:

    class CategorySerializer(serializers.ModelSerializer):
        class Meta:
            model = GoodsCategory
            fields = '__all__'
    
    
    class GoodsSerializer(serializers.ModelSerializer):
        # 覆盖外键字段
        category = CategorySerializer()
        class Meta:
            model = Goods
            fields = '__all__'

    3、drf的GenericView实现商品列表页面

      GenericView继承APIview,封装了很多方法,比APIview更加好用,而且ListModelMixin里面list方法帮我们做好了分页和序列化的功能,只要调用即可:

     1 class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
     2     """商品列表页面"""
     3 
     4     # 查询集,查询所有的商品
     5     queryset = Goods.objects.all()
     6 
     7     # 序列化
     8     serializer_class = GoodsSerializer
     9 
    10     def get(self, request, *args, **kwargs):
    11         return self.list(request, *args, **kwargs)

      上面的代码可以直接继承ListAPIView,这个类直接继承了mixins.ListModelMixin和generics.GenericAPIView,并且写好了get方法,看源码:

    1 class GoodsListView(generics.ListAPIView):
    2     """商品列表页面"""
    3 
    4     queryset = Goods.objects.all()
    5     serializer_class = GoodsSerializer

      现在之后三行就将数据返回了。

    4、分页功能

      在rest_framework的源码文件中默认是没有开启分页功能的,需要自己在settings.py中配置:

    1 # rest_framework分页
    2 REST_FRAMEWORK = {
    3     'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    4     'PAGE_SIZE': 10,
    5 }

      分页也可以自定义,在views.py中自定义分页信息:

     1 class GoodsPagination(PageNumberPagination):
     2     """商品自定义分页"""
     3 
     4     page_size = 10  # 每页显示个数
     5     page_size_query_param = 'page_size'  # 动态改变每页显示的个数
     6     page_query_param = 'page'  # 页码参数
     7     max_page_size = 100  # 最多显示页数
     8 
     9 
    10 class GoodsListView(generics.ListAPIView):
    11     """商品列表页面"""
    12 
    13     queryset = Goods.objects.all()
    14     serializer_class = GoodsSerializer
    15 
    16     # 分页
    17     pagination_class = GoodsPagination

      现在在settings.py中的配置就可以注释掉了:

    5、drf的viewsets和router完成商品列表页面

    1 class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    2     """商品列表页面"""
    3 
    4     pagination_class = GoodsPagination
    5     queryset = Goods.objects.all().order_by('id')  # 必须定义一个默认的排序,否则会报错
    6     serializer_class = GoodsSerializer

      通过router注册url:

     1 from goods.views import GoodsListViewSet
     2 from rest_framework.routers import DefaultRouter
     3 
     4 router = DefaultRouter()
     5 
     6 
     7 router.register(r'goods', GoodsListViewSet)  # 商品列表页
     8 
     9 urlpatterns = [
    11     re_path('^', include(router.urls)),  # 所有接口url
    12 ]

    6、drf的APIView、GenericView、viewsets和router的原理分析

      GenericViewSet是最高的一层,往下依次是GenericAPIView、APIView和django的View,这些view的功能不同,主要体现在mixin的存在,mixins总共有以下五种:

    1. CreateModelMixin
    2. ListModelMixin
    3. UpdateModelMixin
    4. RetrieveModelMixin
    5. DestoryModelMixin

      以上面的ListModelMixin为例,继承它之后,就可以将get方法和商品的列表关联起来,还有其中的分页功能。

      一般的话都是用viewsets,ViewSet类与View类几乎是相同的,其提供的是read或update这些操作,而不是get或put等HTTP动作。同时,ViewSet为我们提供了默认的URL结构, 使得我们能更专注于API本身。

       Router提供了一种简单,快速,集成的方式来定义一系列的urls。

    7、drf的过滤功能

      将django_filters注册到app中:

    1 INSTALLED_APPS = [
    2      'django_filters',
    3 ]

      在goods下新建filter.py文件,自定义一个过滤器:

     1 import django_filters
     2 
     3 from .models import Goods
     4 
     5 
     6 class GoodsFilter(django_filters.rest_framework.FilterSet):
     7     """商品过滤"""
     8 
     9     # name是要过滤的字段,lookup是执行的行为
    10     price_min = django_filters.NumberFilter(field_name="shop_price", lookup_expr='gte')
    11     price_max = django_filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
    12 
    13     class Meta:
    14         model = Goods
    15         fields = ['price_min', 'price_max']

      然后在商品列表接口中增加过滤功能:

     1 class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
     2     """商品列表页面"""
     3 
     4     pagination_class = GoodsPagination
     5     queryset = Goods.objects.all().order_by('id')  # 必须定义一个默认的排序,否则会报错
     6     serializer_class = GoodsSerializer
     7     filter_backends = (DjangoFilterBackend,)
     8 
     9     # 自定义过滤类
    10     filter_class = GoodsFilter

    8、drf的搜索和排序

      在商品列表接口中完善搜索功能:

     1 class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
     2     """商品列表页面"""
     3 
     4     pagination_class = GoodsPagination
     5     queryset = Goods.objects.all().order_by('id')  # 必须定义一个默认的排序,否则会报错
     6     serializer_class = GoodsSerializer
     7     filter_backends = (DjangoFilterBackend, filters.SearchFilter)
     8 
     9     # 自定义过滤类
    10     filter_class = GoodsFilter
    11 
    12     # 搜索,=name表示精确搜索,也可以使用正则
    13     search_fields = ('=name', 'goods_brief')

      完善排序功能:

     1 class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
     2     """商品列表页面"""
     3 
     4     pagination_class = GoodsPagination
     5     queryset = Goods.objects.all().order_by('id')  # 必须定义一个默认的排序,否则会报错
     6     serializer_class = GoodsSerializer
     7     filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
     8 
     9     # 自定义过滤类
    10     filter_class = GoodsFilter
    11 
    12     # 搜索,=name表示精确搜索,也可以使用正则
    13     search_fields = ('=name', 'goods_brief')
    14 
    15     # 排序
    16     ordering_fields = ('sold_num', 'add_time')

  • 相关阅读:
    第一个 Python 程序
    Qt之字体文件(TTF)
    Memcached
    Qt之QtSoap(访问WebService)
    Crypto++编译使用
    Memcached
    Windows下编译OpenSSL
    基于Core Text实现的TXT电子书阅读器
    java代码获取jdbc链接properties
    ext树表+ZeroClipboard复制链接功能
  • 原文地址:https://www.cnblogs.com/Sweltering/p/10016203.html
Copyright © 2011-2022 走看看