Django+Vue打造购物网站(三)
商品列表页
通过商品列表页面来学习drf
django的view实现商品列表页
在goods目录下新建一个views_base.py文件,用来区分drf的view和Dajngo自带的view的区别
利用Django的view实现返回json数据
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/9/20 下午 01:16
# @Author  : gao
# @File    : views_base.py
from django.views.generic.base import View
from goods.models import Goods
class GoodsListView(View):
    def get(self, request):
        # 通过django的view实现商品列表页
        json_list = []
        # 获取所有商品
        goods = Goods.objects.all()
        for good in goods:
            json_dict = {}
            # 获取商品的每个字段,键值对形式
            json_dict['name'] = good.name
            json_dict['category'] = good.category.name
            json_dict['market_price'] = good.market_price
            json_list.append(json_dict)
        from django.http import HttpResponse
        import json
        # 返回json,一定要指定类型content_type='application/json'
        return HttpResponse(json.dumps(json_list), content_type='application/json')
配置url
    path('goods/', GoodsListView.as_view(), name='goods'),
通过浏览器,可以获取商品列表信息的json数据

好像还可以,这里继续添加数据
json_dict["add_time"] = good.add_time
浏览器访问

我们会发现报错了,这种方法是行不通的
django的serializer序列化model
model_to_dict
当字段比较多时,一个字段一个字段的提取很麻烦,可以用model_to_dict,将model整个转化为dict
class GoodsListView(View):
    def get(self, request):
        # 通过django的view实现商品列表页
        json_list = []
        # 获取所有商品
        goods = Goods.objects.all()
        # for good in goods:
        #     json_dict = {}
        #     #获取商品的每个字段,键值对形式
        #     json_dict['name'] = good.name
        #     json_dict['category'] = good.category.name
        #     json_dict['market_price'] = good.market_price
        #     json_list.append(json_dict)
        from django.forms.models import model_to_dict
        for good in goods:
            json_dict = model_to_dict(good)
            json_list.append(json_dict)
        from django.http import HttpResponse
        import json
        # 返回json,一定要指定类型content_type='application/json'
        return HttpResponse(json.dumps(json_list), content_type='application/json')
打开浏览器访问

发现依然报错,ImageFieldFile 和add_time字段不能序列化
这种方法依然有局限性
django serializer
class GoodsListView(View):
    def get(self, request):
        # 通过django的view实现商品列表页
        json_list = []
        # 获取所有商品
        goods = Goods.objects.all()
        # for good in goods:
        #     json_dict = {}
        #     #获取商品的每个字段,键值对形式
        #     json_dict['name'] = good.name
        #     json_dict['category'] = good.category.name
        #     json_dict['market_price'] = good.market_price
        #     json_list.append(json_dict)
        import json
        from django.core import serializers
        from django.http import JsonResponse
        json_data = serializers.serialize('json', goods)
        json_data = json.loads(json_data)
        return JsonResponse(json_data, safe=False)

看着效果挺不错的,数据都加载进来了,但是缺点也挺明显的
- 字段是写死的,不灵活
- image字段不完整
这些缺点drf都可以帮我们来完成
drf实现列表页
安装插件
pip install coreapi                         drf的文档支持
pip install django-guardian           drf对象级别的权限支持
APIview方式实现商品列表页
配置urls
    path('api-auth/',include('rest_framework.urls')),
    path('docs/',include_docs_urls(title='生鲜超市')),
配置rest_framework
INSTALLED_APPS = [
    'rest_framework',
]
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()
goods/views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from goods.models import Goods
from goods.serializers import GoodsSerializer
class GoodsListView(APIView):
    '''
    商品列表
    '''
    def get(self, request, format=None):
        goods = Goods.objects.all()
        goods_serialzer = GoodsSerializer(goods, many=True)
        return Response(goods_serialzer.data)
修改urls的GoodsListView的引入
浏览器访问

这是drf渲染的界面
可以看到image字段已经帮我们补全了
drf的Modelserializer实现商品列表页
上面是用Serializer实现的,需要自己手动添加字段,如果用Modelserializer,会更加的方便,直接用__all__就可以全部序列化
serializers.py
from rest_framework import serializers
from goods.models import Goods
# class GoodsSerializer(serializers.Serializer):
#     name = serializers.CharField(required=True, max_length=100)
#     click_num = serializers.IntegerField(default=0)
#     goods_front_image = serializers.ImageField()
# ModelSerializer实现商品列表页
class GoodsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = '__all__'

外键被序列化为id,如果想要显示外键字段的信息,可以使用Serialzer的嵌套功能
serializers.py
class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategory
        fields = "__all__"
# ModelSerializer实现商品列表页
class GoodsSerializer(serializers.ModelSerializer):
    # 覆盖外键字段
    category = CategorySerializer()
    class Meta:
        model = Goods
        fields = '__all__'

乐意看到,category字段显示的已经是详细信息了,不再是一个id了
GenericView实现商品列表页
mixins和generic一起使用
GenericAPIView继承APIView,封装了很多方法,比APIView功能更强大
用的时候需要定义queryset和serializer_class
GenericAPIView里面默认为空
ListModelMixin里面list方法帮我们做好了分页和序列化的工作,只要调用就好了
from rest_framework import mixins, generics
from rest_framework.response import Response
from rest_framework.views import APIView
from goods.models import Goods
from goods.serializers import GoodsSerializer
class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
    '''
    商品列表页
    '''
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
如果不写get方法的话,是没法通过get请求访问的
这样看起来代码比之前的简洁一点了
我们还可以通过给继承ListAPIView来让代码更加简介
ListAPIView源代码如下
class ListAPIView(mixins.ListModelMixin,
                  GenericAPIView):
    """
    Concrete view for listing a queryset.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
可以看到ListAPIView继承了mixins.ListModelMixin和generics.GenericAPIView
而且帮我们实现了get方法,和我们自己写的get方法一样
这样的话,我们的代码就长这样了
class GoodsListView(generics.ListAPIView):
    '''
    商品列表页
    '''
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
运行结果和之前的一样,但是代码只有两行
添加分页功能
官网示例:
http://www.django-rest-framework.org/api-guide/pagination/#setting-the-pagination-style
settings.py
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 1,
}
DEFAULT_PAGINATION_CLASS: 分页所使用的类
PAGE_SIZE: 每页显示的数量
下面的图片路径也已经进行了补全,连域名都加上了

运行访问时可能会有一个警告
UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <class 'goods.models.Goods'> QuerySet.
是因为我们没有对取出的数据进行排序
    queryset = Goods.objects.all().order_by('id')
自定义分页功能
http://www.django-rest-framework.org/api-guide/pagination/#modifying-the-pagination-style
首先注释掉settings.py中的分页
goods/views.py
class GoodsPagination(PageNumberPagination):
    '''
    商品列表自定义分页
    '''
    # 默认每页显示的个数
    page_size = 10
    # 可以动态改变每页显示的个数
    page_size_query_param = 'page_size'
    # 页码参数 http://127.0.0.1:8000/goods/?page=2&page_size=30
    page_query_param = 'page'
    # 每页最多能显示多少体条
    # 仅当 page_size_query_param 设置时有效
    max_page_size = 20
class GoodsListView(generics.ListAPIView):
    '''
    商品列表页
    '''
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
page_size_query_param: 默认每页显示的是10条数据,可以通过这个变量来改变每页显示的数量
http://127.0.0.1:8000/goods/?page=2&page_size=30
这个数量又受到max_page_size这个变量的控制
当我们想要每页显示30条数据的时候,明显的>20,所以每页只显示20条数据
viewsets和router完成商品列表页
主要用到viewsets中的GenericViewSet
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default,
    but does include the base set of generic view behavior, such as
    the `get_object` and `get_queryset` methods.
    """
    pass
ViewSetMixin中重写了as_view方法,可以将action和函数进行绑定
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    '''
    商品列表页
    '''
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
urls.py
from goods.views import GoodsListViewSet
goods_list = GoodsListViewSet.as_view({
    'get': 'list',
})
path('goods/', goods_list, name='goods'),
通过viewset的as_view方法,将get请求和list方法进行绑定
但是这样的话需要手动绑定比较麻烦,drf提供了一种更简单的使用方法
http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#using-routers
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'goods', GoodsListViewSet, base_name='goods')
re_path('^', include(router.urls)),
drf的APIView、GenericView、viewsets和router的简单分析
这是GoodsListViewSet的继承关系

GenericViewSet 是最高的一层
往下
GenericViewSet(viewsets) ----drf
GenericAPIView ---drf
APIView ---drf
View ----django
这些view功能的不同,主要的是有mixin的存在
mixins总共有五种:
  CreateModelMixin
  ListModelMixin
  UpdateModelMixin
  RetrieveModelMixin
  DestoryModelMixin
Router提供了自动绑定的功能
drf的request和response介绍
http://www.django-rest-framework.org/api-guide/requests/
http://www.django-rest-framework.org/api-guide/responses/
drf的过滤
在使用drf的过滤器之前,请先安装django-filter
pip install django-filter
http://www.django-rest-framework.org/api-guide/filtering/#api-guide
添加到INSTALLED_APPS里面
INSTALLED_APPS = [
     'django_filters',
]
在goods目录下新建filters.py
import django_filters
from goods.models import Goods
class GoodsFilter(django_filters.rest_framework.FilterSet):
    '''
    商品过滤的类
    '''
    # 两个参数,field_name是要过滤的字段,lookup是执行的行为,‘小与等于本店价格’
    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']
goods/views.py
from django_filters.rest_framework import DjangoFilterBackend
from goods.filters import GoodsFilter
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    '''
    商品列表页
    '''
    queryset = Goods.objects.all().order_by('id')
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    filter_backends = (DjangoFilterBackend,)
    # 自定义过滤器
    filter_class = GoodsFilter

drf的搜索和排序
http://www.django-rest-framework.org/api-guide/filtering/#searchfilter
http://www.django-rest-framework.org/api-guide/filtering/#orderingfilter
这里的排序,搜索使用的都是rest_framework里面的包,而不是django_filters里面的包
from rest_framework.filters import SearchFilter, OrderingFilter
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    '''
    商品列表页, 分页, 过滤, 排序
    '''
    queryset = Goods.objects.all().order_by('id')
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
    # 自定义过滤器
    filter_class = GoodsFilter
    # 搜索,默认模糊查询
    search_fields = ('name', 'goods_brief')
    # 排序
    ordering_fields = ('shop_price', 'add_time')

短短几行代码,就完成了商品列表页的分页,过滤,排序功能
Django+Vue打造购物网站(三)的更多相关文章
- Django+Vue打造购物网站(十)
		首页.商品数量.缓存和限速功能开发 将环境切换为本地,vue也切换为本地 轮播图 goods/serializers.py class BannerSerializer(serializers.Mod ... 
- Django+Vue打造购物网站(九)
		支付宝沙箱环境配置 https://openhome.alipay.com/platform/appDaily.htm?tab=info 使用支付宝账号进行登陆 RSA私钥及公钥生成 https:// ... 
- Django+Vue打造购物网站(四)
		首页商品类别数据显示 商品分类接口 大概需要两个,一个显示三个类别 一个显示类别及类别下的全部商品 现在开始写商品的接口 首先编写三个分类的serializer class CategorySeria ... 
- Django+Vue打造购物网站(五)
		注册和登陆 drf的认证 http://www.django-rest-framework.org/api-guide/authentication/ settings.py文件的配置 INSTALL ... 
- Django+Vue打造购物网站(八)
		购物车.订单管理和远程调试 添加商品到购物车 trade/serializers.py from rest_framework import serializers from goods.models ... 
- Django+Vue打造购物网站(二)
		配置后台管理 xadmin直接使用之前的在线教育的那个就可以了 users/adminx.py #!/usr/bin/env python # -*- coding: utf-8 -*- # @Tim ... 
- Django+Vue打造购物网站(十一)
		第三方登录 微博创建应用,修改回调地址 http://open.weibo.com/authentication 安装第三方登录插件 https://github.com/python-social- ... 
- Django+Vue打造购物网站(一)
		环境搭建 python == 3.6 Django == 2.0 创建工程 django-admin startproject MxShop 配置setting.py文件 # 数据库 DATABASE ... 
- Django+Vue打造购物网站(七)
		个人中心功能开发 drf文档注释 http://www.django-rest-framework.org/topics/documenting-your-api/ 动态设置serializer和pe ... 
随机推荐
- Westore 1.0 正式发布 - 小程序框架一个就够
			世界上最小却强大的小程序框架 - 100多行代码搞定全局状态管理和跨页通讯 Github: https://github.com/dntzhang/westore 众所周知,小程序通过页面或组件各自的 ... 
- Django 中间件版登录验证
			中间件版的登录验证需要依靠session,所以数据库中要有django_session表. urls.py # urls.py from django.conf.urls import url fro ... 
- Python—包介绍
			包(Package) 当你的模块文件越来越多,就需要对模块文件进行划分,比如把负责跟数据库交互的都放一个文件夹,把与页面交互相关的放一个文件夹, . └── my_proj ├── crm #代码目录 ... 
- 最短路问题 Floyd+Dijkstra+SPFA
			参考博客:https://blog.csdn.net/qq_35644234/article/details/60875818 题目来源:http://acm.hdu.edu.cn/showprobl ... 
- c++入门之结构体初步
			结构体实际上是一种数据结构的雏形,对结构体的灵活使用很多时候可以带来很多便利.下面给出一个关于结构体的程序: #include "iostream" # include " ... 
- Day15  Python基础之logging模块(十三)
			参考源:http://www.cnblogs.com/yuanchenqi/articles/5732581.html logging模块 (****重点***) 一 (简单应用) import lo ... 
- Podfile文件用法详解
			https://www.jianshu.com/p/b8b889610b7e 2018.01.09 15:51* 字数 2343 阅读 6263评论 3喜欢 34 前言 iOS开发会经常用到cocoa ... 
- debian6保存iptables规则
			iptables规则不保存,一旦机器重启规则就清空了,所以需要保存: iptables-save >/etc/iptables-script vi /etc/rc.local 然后在文件中输入: ... 
- 11-vue的使用
			一.安装 对于新手来说,强烈建议大家使用<script>引入 二. 引入vue.js文件 我们能发现,引入vue.js文件之后,Vue被注册为一个全局的变量,它是一个构造函数. 三.使用V ... 
- Spring.profile配合Jenkins发布War包,实现开发、测试和生产环境的按需切换
			前两篇不错 Spring.profile实现开发.测试和生产环境的配置和切换 - Strugglion - 博客园https://www.cnblogs.com/strugglion/p/709102 ... 
