商品列表页

通过商品列表页面来学习drf

django的view实现商品列表页

在goods目录下新建一个views_base.py文件,用来区分drf的view和Dajngo自带的view的区别

利用Django的view实现返回json数据

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # @Time : 2018/9/20 下午 01:16
  4. # @Author : gao
  5. # @File : views_base.py
  6. from django.views.generic.base import View
  7. from goods.models import Goods
  8. class GoodsListView(View):
  9. def get(self, request):
  10. # 通过django的view实现商品列表页
  11. json_list = []
  12. # 获取所有商品
  13. goods = Goods.objects.all()
  14. for good in goods:
  15. json_dict = {}
  16. # 获取商品的每个字段,键值对形式
  17. json_dict['name'] = good.name
  18. json_dict['category'] = good.category.name
  19. json_dict['market_price'] = good.market_price
  20. json_list.append(json_dict)
  21. from django.http import HttpResponse
  22. import json
  23. # 返回json,一定要指定类型content_type='application/json'
  24. return HttpResponse(json.dumps(json_list), content_type='application/json')

配置url

  1. path('goods/', GoodsListView.as_view(), name='goods'),

通过浏览器,可以获取商品列表信息的json数据

好像还可以,这里继续添加数据

  1. json_dict["add_time"] = good.add_time

浏览器访问

我们会发现报错了,这种方法是行不通的

django的serializer序列化model

model_to_dict

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

  1. class GoodsListView(View):
  2. def get(self, request):
  3. # 通过django的view实现商品列表页
  4. json_list = []
  5. # 获取所有商品
  6. goods = Goods.objects.all()
  7. # for good in goods:
  8. # json_dict = {}
  9. # #获取商品的每个字段,键值对形式
  10. # json_dict['name'] = good.name
  11. # json_dict['category'] = good.category.name
  12. # json_dict['market_price'] = good.market_price
  13. # json_list.append(json_dict)
  14. from django.forms.models import model_to_dict
  15. for good in goods:
  16. json_dict = model_to_dict(good)
  17. json_list.append(json_dict)
  18. from django.http import HttpResponse
  19. import json
  20. # 返回json,一定要指定类型content_type='application/json'
  21. return HttpResponse(json.dumps(json_list), content_type='application/json')

打开浏览器访问

发现依然报错,ImageFieldFile 和add_time字段不能序列化

这种方法依然有局限性

django serializer
  1. class GoodsListView(View):
  2. def get(self, request):
  3. # 通过django的view实现商品列表页
  4. json_list = []
  5. # 获取所有商品
  6. goods = Goods.objects.all()
  7. # for good in goods:
  8. # json_dict = {}
  9. # #获取商品的每个字段,键值对形式
  10. # json_dict['name'] = good.name
  11. # json_dict['category'] = good.category.name
  12. # json_dict['market_price'] = good.market_price
  13. # json_list.append(json_dict)
  14. import json
  15. from django.core import serializers
  16. from django.http import JsonResponse
  17. json_data = serializers.serialize('json', goods)
  18. json_data = json.loads(json_data)
  19. return JsonResponse(json_data, safe=False)

看着效果挺不错的,数据都加载进来了,但是缺点也挺明显的

  1. 字段是写死的,不灵活
  2. image字段不完整

这些缺点drf都可以帮我们来完成

drf实现列表页

安装插件

  1. pip install coreapi drf的文档支持
  2. pip install django-guardian drf对象级别的权限支持
APIview方式实现商品列表页

配置urls

  1. path('api-auth/',include('rest_framework.urls')),
  2. path('docs/',include_docs_urls(title='生鲜超市')),

配置rest_framework

  1. INSTALLED_APPS = [
  2. 'rest_framework',
  3. ]

goods文件夹下面新建serializers.py

这里先写三个字段

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

goods/views.py

  1. from rest_framework.response import Response
  2. from rest_framework.views import APIView
  3. from goods.models import Goods
  4. from goods.serializers import GoodsSerializer
  5. class GoodsListView(APIView):
  6. '''
  7. 商品列表
  8. '''
  9. def get(self, request, format=None):
  10. goods = Goods.objects.all()
  11. goods_serialzer = GoodsSerializer(goods, many=True)
  12. return Response(goods_serialzer.data)

修改urls的GoodsListView的引入

浏览器访问

这是drf渲染的界面

可以看到image字段已经帮我们补全了

drf的Modelserializer实现商品列表页

上面是用Serializer实现的,需要自己手动添加字段,如果用Modelserializer,会更加的方便,直接用__all__就可以全部序列化

serializers.py

  1. from rest_framework import serializers
  2. from goods.models import Goods
  3. # class GoodsSerializer(serializers.Serializer):
  4. # name = serializers.CharField(required=True, max_length=100)
  5. # click_num = serializers.IntegerField(default=0)
  6. # goods_front_image = serializers.ImageField()
  7. # ModelSerializer实现商品列表页
  8. class GoodsSerializer(serializers.ModelSerializer):
  9. class Meta:
  10. model = Goods
  11. fields = '__all__'

外键被序列化为id,如果想要显示外键字段的信息,可以使用Serialzer的嵌套功能

serializers.py

  1. class CategorySerializer(serializers.ModelSerializer):
  2. class Meta:
  3. model = GoodsCategory
  4. fields = "__all__"
  5. # ModelSerializer实现商品列表页
  6. class GoodsSerializer(serializers.ModelSerializer):
  7. # 覆盖外键字段
  8. category = CategorySerializer()
  9. class Meta:
  10. model = Goods
  11. fields = '__all__'

乐意看到,category字段显示的已经是详细信息了,不再是一个id了

GenericView实现商品列表页

mixins和generic一起使用

GenericAPIView继承APIView,封装了很多方法,比APIView功能更强大

用的时候需要定义queryset和serializer_class

GenericAPIView里面默认为空

ListModelMixin里面list方法帮我们做好了分页和序列化的工作,只要调用就好了

  1. from rest_framework import mixins, generics
  2. from rest_framework.response import Response
  3. from rest_framework.views import APIView
  4. from goods.models import Goods
  5. from goods.serializers import GoodsSerializer
  6. class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
  7. '''
  8. 商品列表页
  9. '''
  10. queryset = Goods.objects.all()
  11. serializer_class = GoodsSerializer
  12. def get(self, request, *args, **kwargs):
  13. return self.list(request, *args, **kwargs)

如果不写get方法的话,是没法通过get请求访问的

这样看起来代码比之前的简洁一点了

我们还可以通过给继承ListAPIView来让代码更加简介

ListAPIView源代码如下

  1. class ListAPIView(mixins.ListModelMixin,
  2. GenericAPIView):
  3. """
  4. Concrete view for listing a queryset.
  5. """
  6. def get(self, request, *args, **kwargs):
  7. return self.list(request, *args, **kwargs)

可以看到ListAPIView继承了mixins.ListModelMixingenerics.GenericAPIView

而且帮我们实现了get方法,和我们自己写的get方法一样

这样的话,我们的代码就长这样了

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

运行结果和之前的一样,但是代码只有两行

添加分页功能

官网示例:

http://www.django-rest-framework.org/api-guide/pagination/#setting-the-pagination-style

settings.py

  1. REST_FRAMEWORK = {
  2. 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
  3. 'PAGE_SIZE': 1,
  4. }

DEFAULT_PAGINATION_CLASS: 分页所使用的类

PAGE_SIZE: 每页显示的数量

下面的图片路径也已经进行了补全,连域名都加上了

运行访问时可能会有一个警告

UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <class 'goods.models.Goods'> QuerySet.

是因为我们没有对取出的数据进行排序

  1. 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

  1. class GoodsPagination(PageNumberPagination):
  2. '''
  3. 商品列表自定义分页
  4. '''
  5. # 默认每页显示的个数
  6. page_size = 10
  7. # 可以动态改变每页显示的个数
  8. page_size_query_param = 'page_size'
  9. # 页码参数 http://127.0.0.1:8000/goods/?page=2&page_size=30
  10. page_query_param = 'page'
  11. # 每页最多能显示多少体条
  12. # 仅当 page_size_query_param 设置时有效
  13. max_page_size = 20
  14. class GoodsListView(generics.ListAPIView):
  15. '''
  16. 商品列表页
  17. '''
  18. queryset = Goods.objects.all()
  19. serializer_class = GoodsSerializer
  20. 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

  1. class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
  2. """
  3. The GenericViewSet class does not provide any actions by default,
  4. but does include the base set of generic view behavior, such as
  5. the `get_object` and `get_queryset` methods.
  6. """
  7. pass

ViewSetMixin中重写了as_view方法,可以将action和函数进行绑定

  1. class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
  2. '''
  3. 商品列表页
  4. '''
  5. queryset = Goods.objects.all()
  6. serializer_class = GoodsSerializer
  7. pagination_class = GoodsPagination

urls.py

  1. from goods.views import GoodsListViewSet
  2. goods_list = GoodsListViewSet.as_view({
  3. 'get': 'list',
  4. })
  5. 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

  1. from rest_framework.routers import DefaultRouter
  2. router = DefaultRouter()
  3. router.register(r'goods', GoodsListViewSet, base_name='goods')
  4. 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

  1. pip install django-filter

http://www.django-rest-framework.org/api-guide/filtering/#api-guide

django-filter官网

添加到INSTALLED_APPS里面

  1. INSTALLED_APPS = [
  2. 'django_filters',
  3. ]

在goods目录下新建filters.py

  1. import django_filters
  2. from goods.models import Goods
  3. class GoodsFilter(django_filters.rest_framework.FilterSet):
  4. '''
  5. 商品过滤的类
  6. '''
  7. # 两个参数,field_name是要过滤的字段,lookup是执行的行为,‘小与等于本店价格’
  8. price_min = django_filters.NumberFilter(field_name="shop_price", lookup_expr='gte')
  9. price_max = django_filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
  10. class Meta:
  11. model = Goods
  12. fields = ['price_min', 'price_max']

goods/views.py

  1. from django_filters.rest_framework import DjangoFilterBackend
  2. from goods.filters import GoodsFilter
  3. class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
  4. '''
  5. 商品列表页
  6. '''
  7. queryset = Goods.objects.all().order_by('id')
  8. serializer_class = GoodsSerializer
  9. pagination_class = GoodsPagination
  10. filter_backends = (DjangoFilterBackend,)
  11. # 自定义过滤器
  12. 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里面的包

  1. from rest_framework.filters import SearchFilter, OrderingFilter
  2. class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
  3. '''
  4. 商品列表页, 分页, 过滤, 排序
  5. '''
  6. queryset = Goods.objects.all().order_by('id')
  7. serializer_class = GoodsSerializer
  8. pagination_class = GoodsPagination
  9. filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
  10. # 自定义过滤器
  11. filter_class = GoodsFilter
  12. # 搜索,默认模糊查询
  13. search_fields = ('name', 'goods_brief')
  14. # 排序
  15. ordering_fields = ('shop_price', 'add_time')

短短几行代码,就完成了商品列表页的分页,过滤,排序功能

Django+Vue打造购物网站(三)的更多相关文章

  1. Django+Vue打造购物网站(十)

    首页.商品数量.缓存和限速功能开发 将环境切换为本地,vue也切换为本地 轮播图 goods/serializers.py class BannerSerializer(serializers.Mod ...

  2. Django+Vue打造购物网站(九)

    支付宝沙箱环境配置 https://openhome.alipay.com/platform/appDaily.htm?tab=info 使用支付宝账号进行登陆 RSA私钥及公钥生成 https:// ...

  3. Django+Vue打造购物网站(四)

    首页商品类别数据显示 商品分类接口 大概需要两个,一个显示三个类别 一个显示类别及类别下的全部商品 现在开始写商品的接口 首先编写三个分类的serializer class CategorySeria ...

  4. Django+Vue打造购物网站(五)

    注册和登陆 drf的认证 http://www.django-rest-framework.org/api-guide/authentication/ settings.py文件的配置 INSTALL ...

  5. Django+Vue打造购物网站(八)

    购物车.订单管理和远程调试 添加商品到购物车 trade/serializers.py from rest_framework import serializers from goods.models ...

  6. Django+Vue打造购物网站(二)

    配置后台管理 xadmin直接使用之前的在线教育的那个就可以了 users/adminx.py #!/usr/bin/env python # -*- coding: utf-8 -*- # @Tim ...

  7. Django+Vue打造购物网站(十一)

    第三方登录 微博创建应用,修改回调地址 http://open.weibo.com/authentication 安装第三方登录插件 https://github.com/python-social- ...

  8. Django+Vue打造购物网站(一)

    环境搭建 python == 3.6 Django == 2.0 创建工程 django-admin startproject MxShop 配置setting.py文件 # 数据库 DATABASE ...

  9. Django+Vue打造购物网站(七)

    个人中心功能开发 drf文档注释 http://www.django-rest-framework.org/topics/documenting-your-api/ 动态设置serializer和pe ...

随机推荐

  1. 我的微信小程序第二篇

    在上一篇<我的微信小程序第一篇(入门)>中,很多人问我什么是微信小程序,在这里我要说一下这个是我的失误啦,我默认大家都知道微信小程序,其实可能行内人士都知道小程序,好多非行内朋友可能平时不 ...

  2. 小P的字符串

    题目描述 小P最近在研究字符编码,给出一串由0.1组成的字符串,从中任意进行截取,如果截取的字符串对应一个英文字母的ASCII值,小P就把这个0.1串叫字母子串,问给定的字符串最多能截取出多少个字母子 ...

  3. java得到日期相减的天数

    /** * <li>功能描述:时间相减得到天数 * @param beginDateStr * @param endDateStr * @return * long * @author A ...

  4. php使用gd库输出中文内容的图片

    正如标题所说那样,本文只讨论输出内容全部为中文或者包含中文的情况.如果内容全是字母或者其他字符的话,可以参考这篇博客:生成验证码 问题 此处要注意,标题中为什么要区别windows和linux分别实现 ...

  5. 【转】linux下查看磁盘分区的文件系统格式

    https://www.cnblogs.com/youbiyoufang/p/7607174.html

  6. Memcache之安装篇

    本篇文章会介绍memcache在Windows和Linux下的具体安装过程,详细的记录其中的流程内容,帮助小伙伴们快速的搭建起memcache服务,废话少说,直接上!!! Windows: Memca ...

  7. js-其他跨域技术(JSONP`Comet)

    ###1.  JSONP JSONP由两部分组成:回调函数和数据 JSONP是通过动态<script>元素来使用的,使用时可以为src属性指定一个跨域URL eg: function ha ...

  8. Azure系列2.1.5 —— BlobOutputStream

    (小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...

  9. C++类的内存结构

    摘自Jerry19880126 简单类 class Base { int a; int b; public: void CommonFunction(); }; 简单类继承 class Derived ...

  10. day 7-15 表与表之间的关系

    一. 前言 表与 表之间有3种对应关系,分别是: 多对一:一张表中的一个字段中的多个值对应另外一张表中的一个字段值.(多个学生,可以学习同一门课程) 多对多;一张表中的一个字段值对应另外一张表中的多个 ...