前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue+Django2.0 REST framework 打造前后端分离的生鲜电商项目(五)商品列表页

Vue+Django2.0 REST framework 打造前后端分离的生鲜电商项目(五)商品列表页

作者头像
玩蛇的胖纸
发布2018-06-08 13:00:41
4.7K0
发布2018-06-08 13:00:41
举报

一、Django2.0的view实现商品列表页

算是对以前django知识的一个回顾,方便跟下面的drf(Django REST framework)实现商品列表页作对比

1.在apps/goods下新建views_base.py文件

代码语言:javascript
复制
 1 import json
 2 from django.views.generic.base import View
 3 
 4 from .models import Goods
 5 
 6 
 7 class GoodsListView(View):
 8     def get(self,request):
 9         """
10         通过django的view实现商品列表页
11         :param request:
12         :return:
13         """
14         json_list=[]
15         goods=Goods.objects.all()[:10]
16 
17         # 最传统方案,麻烦且add_time序列化会报错
18         # for good in goods:
19         #     json_dict={}
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         # 改进方案,但是ImageFieldFile无法进行序列化,报错
26         # from django.forms.models import model_to_dict
27         # for good in goods:
28         #     json_dict=model_to_dict(good)
29         #     json_list.append(json_dict)
30 
31         from django.core import serializers
32         json_data=serializers.serialize("json",goods)
33 
34         # 前两个方案使用的代码
35         # from django.http import HttpResponse
36         # return HttpResponse(json.dumps(json_list),content_type="application/json")
37 
38         from django.http import JsonResponse
39         return JsonResponse(json_data,safe=False)

2.在urls.py设置路由

代码语言:javascript
复制
 1 from django.urls import path,include
 2 import xadmin
 3 #
 4 from django.views.static import serve
 5 from MXshop.settings import MEDIA_ROOT
 6 
 7 from goods.views_base import GoodsListView
 8 
 9 urlpatterns = [
10     path('xadmin/', xadmin.site.urls),
11     path('ueditor/',include('DjangoUeditor.urls')),
12     #配置上传文件的访问处理函数
13     path('media/<path:path>',serve,{'document_root':MEDIA_ROOT}),
14 
15     path('goods', GoodsListView.as_view(),name="goods-list"),
16 ]

3.启动项目,访问:http://127.0.0.1:8000/goods  即可看到从后端传过来的,包含了goods数据信息的json字符串。

小贴士:怎样理解json?

在views_base中,我被 JsonResponse,HttpResponse这两个模块之间的有什么不同所引起好奇心,都是返回字符串,一个可以返回json,而另一个需要添加一些设置才能返回json。那么何为json?我特意去查了一下,结果为:

代码语言:javascript
复制
1 JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。
2 它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。

显然,这解释不像人话,于是我觉得自己动手丰衣足食才是硬道理。基于一条真理:

代码语言:javascript
复制
1 网络传输的数据都是字符串!

我将HTTPResponse中除了要返回的字符串,其他参数都删了,代替JsonResponse来作为return值。结果没有报错,于是我打开网页访问:http://127.0.0.1:8000/goods,发现虽然同样传输过来了字符串信息,但是字符串“并不纯”,有一些字符串居然发生了被执行了,换行什么的!于是,我明白了,json是什么?

代码语言:javascript
复制
1 json就是“纯”字符串!将字符串中一切可以被执行的内容(类似于\n)统统转义为不可执行的字符串内容!

二、apiview方式实现商品列表页

1.drf(Django REST framework)所需插件:

代码语言:javascript
复制
1 coreapi(1.32.0+) - 模式生成支持。
2 Markdown(2.1.0+) - 可浏览API的Markdown支持。
3 django-filter(1.0.1+) - 过滤支持。
4 django-crispy-forms - 改进了用于过滤的HTML显示。
5 django-guardian(1.1.1+) - 对象级权限支持。

在pycharm==》files==》setting==》Project==》project interpreter看到已经安装好的插件

其中,已经有了:Markdown、django-filter、django-crispy-forms

安装 django-guardian、coreapi。(有的插件是安装上就可以了,有的不但需要安装,还需要配置,幸好这两个都属于前者。)

 2.实现商品列表页

1.配置 rest_framework

1.在urls.py中

代码语言:javascript
复制
 1 from django.urls import path,include
 2 import xadmin
 3 #
 4 from django.views.static import serve
 5 from MXshop.settings import MEDIA_ROOT
 6 from goods.views_base import GoodsListView
 7 #
 8 from rest_framework.documentation import include_docs_urls
 9 
10 
11 urlpatterns = [
12 #
13     path('xadmin/', xadmin.site.urls),
14     path('ueditor/',include('DjangoUeditor.urls')),
15     #配置上传文件的访问处理函数
16     path('media/<path:path>',serve,{'document_root':MEDIA_ROOT}),
17     path('goods', GoodsListView.as_view(),name="goods-list"),
18 #
19     path('docs',include_docs_urls(title='慕学生鲜')),
20     path('api-auth/', include('rest_framework.urls',namespace='rest_framework')),
21 ]

2.在settings.py中注册rest_framework

代码语言:javascript
复制
 1 INSTALLED_APPS = [
 2     'django.contrib.admin',
 3     'django.contrib.auth',
 4     'django.contrib.contenttypes',
 5     'django.contrib.sessions',
 6     'django.contrib.messages',
 7     'django.contrib.staticfiles',
 8 
 9     'users.apps.UsersConfig',
10     'goods.apps.GoodsConfig',
11     'trade.apps.TradeConfig',
12     'user_operation.apps.UserOperationConfig',
13 
14     'DjangoUeditor',
15     'crispy_forms',
16     'reversion',
17     'xadmin',
18 #
19     'rest_framework',
20 ]

2.drf写views

在apps/goods下新建serializer.py文件(drf中的serializer.py等同于django中的forms.py)

代码语言:javascript
复制
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()

在apps/goods/views中:

代码语言:javascript
复制
 1 from .serializer import GoodsSerializer
 2 from rest_framework.views import APIView
 3 from rest_framework.response import Response
 4 
 5 from .models import Goods
 6 # Create your views here.
 7 
 8 class GoodsListView(APIView):
 9     """
10     List all snippets, or create a new snippet.
11     """
12     def get(self, request, format=None):
13         goods = Goods.objects.all()[:10]
14         #序列化
15         goods_serializer = GoodsSerializer(goods, many=True)
16         return Response(goods_serializer.data)

再配置一下urls.py

代码语言:javascript
复制
from django.urls import path,include
import xadmin
#
from django.views.static import serve
from MXshop.settings import MEDIA_ROOT
# from goods.views_base import GoodsListView

from rest_framework.documentation import include_docs_urls
from goods.views import GoodsListView

urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    path('ueditor/',include('DjangoUeditor.urls')),
    #配置上传文件的访问处理函数
    path('media/<path:path>',serve,{'document_root':MEDIA_ROOT}),

    path('goods', GoodsListView.as_view(),name="goods-list"),
    path('docs',include_docs_urls(title='慕学生鲜')),
    path('api-auth/', include('rest_framework.urls',namespace='rest_framework')),
]

浏览器访问:http://127.0.0.1:8000/goods 即可看到drf传过去的json数据信息了,而且做了一定程度的渲染。

小贴士:

在访问时,如果没有在xadmin后台退出账号,有可能会报错:

Django rest framework __str__ returned non-string (type NoneType)

是一个bug导致的这个报错:

首先,我们的UserProfile表继承的django/admin自动创建的用户表AbstractUser,

然后,我们在UserProfile表中用__str__返回的是name字段(昵称),而drf在找的是AbstractUser的username字段(用户名),没找到所以报错

解决方法:将UserProfile表中的__str__方法改成返回username:

代码语言:javascript
复制
1     def __str__(self):
2         return self.username

三、drf实现商品列表页的功能

1.ModelSerializer(相当于django中的modelform,但是更加强大)

apps/goods/serializer.py

代码语言:javascript
复制
 1 from rest_framework import serializers
 2 from .models import Goods
 3 
 4 class GoodsSerializer(serializers.ModelSerializer):
 5     class Meta:
 6         model=Goods
 7         #序列化指定字段
 8         #fields=('name','click_num','market_price','add_time')
 9         #序列化全部字段
10         fields="__all__"
11 
12 
13 
14 
15 # class GoodsSerializer(serializers.Serializer):
16 #     name=serializers.CharField(required=True,max_length=100)
17 #     click_num=serializers.IntegerField(default=0)
18 #     goods_front_image=serializers.ImageField()
19 #
20 #     def create(self, validated_data):
21 #         """
22 #         Create and return a new `Snippet` instance, given the validated data.
23 #         """
24 #         return Goods.objects.create(**validated_data)

apps/goods/views.py同样可以使用

代码语言:javascript
复制
from .serializer import GoodsSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status


from .models import Goods
# Create your views here.

class GoodsListView(APIView):
    """
    List all goods
    """
    def get(self, request, format=None):
        goods = Goods.objects.all()[:10]
        goods_serializer = GoodsSerializer(goods, many=True)
        return Response(goods_serializer.data)

    #由于商品都是从后台添加的,不是通过用户从前端增加的,所以商品列表页用不到post
    # def post(self, request, format=None):
    #     serializer = GoodsSerializer(data=request.data)
    #     if serializer.is_valid():
    #         serializer.save()
    #         return Response(serializer.data, status=status.HTTP_201_CREATED)
    #     return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

这时访问:http://127.0.0.1:8000/goods 是跟django中的modelform做到了同样的事儿,但modelserializer可以做到 序列化的嵌套

对apps/goods/serializer.py改写:

代码语言:javascript
复制
 1 from rest_framework import serializers
 2 from .models import Goods,GoodsCategory
 3 
 4 
 5 class CategorySerializer(serializers.ModelSerializer):
 6     class Meta:
 7         model=GoodsCategory
 8         fields="__all__"
 9 
10 
11 class GoodsSerializer(serializers.ModelSerializer):
12     #实例化CategorySerializer
13     category=CategorySerializer()
14     class Meta:
15         model=Goods
16         fields="__all__"

这时访问:http://127.0.0.1:8000/goods ,可以看到,商品列表中,商品的品牌表的数据也都展示了出来。

2.使用mixins让代码变得更简洁

1.精简apps/goods/views.py里面的代码后:

代码语言:javascript
复制
 1 from .serializer import GoodsSerializer
 2 from rest_framework.views import APIView
 3 from rest_framework.response import Response
 4 
 5 #引入两个mixins所需的模块
 6 from rest_framework import mixins
 7 from rest_framework import generics
 8 
 9 from .models import Goods
10 # Create your views here.
11 
12 
13 class GoodsListView(generics.ListAPIView):
14     """
15     List all goods
16     """
17     queryset = Goods.objects.all()[:10]
18     serializer_class = GoodsSerializer

2.drf分页

drf是自带分页功能的,只要在views中进行一下规则的配置,就可以直接调用使用:

代码语言:javascript
复制
 1 from .serializer import GoodsSerializer
 2 from rest_framework.views import APIView
 3 from rest_framework.response import Response
 4 
 5 from rest_framework import mixins
 6 from rest_framework import generics
 7 from rest_framework.pagination import PageNumberPagination
 8 
 9 from .models import Goods
10 # Create your views here.
11 
12 
13 class GoodsPagination(PageNumberPagination):
14     """
15     配置分页规则
16     """
17     page_size = 10
18     page_size_query_param = 'page_size'
19     page_query_param="p"
20     max_page_size = 1000
21 
22 class GoodsListView(generics.ListAPIView):
23     """
24     List all goods
25     """
26     #queryset = Goods.objects.all() 用.all这种获取方法没什么大问题,只不过是没有代表
27     #将所有对象取出,而没有指定顺序,这就使得会出现:UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list
28     #的警告提示,使用下面的办法就会消除这种提示了。
29     queryset = Goods.objects.get_queryset().order_by('id')
30     serializer_class = GoodsSerializer
31     pagination_class = GoodsPagination

重启项目,访问:http://127.0.0.1:8000/goods 即可看到分页效果

3.最重要的viewsets和router(路由器)来实现商品列表页

将apps/goods/views.py改写为:

代码语言:javascript
复制
 1 from .serializer import GoodsSerializer
 2 from rest_framework.views import APIView
 3 from rest_framework.response import Response
 4 
 5 from rest_framework import mixins
 6 from rest_framework import generics
 7 from rest_framework.pagination import PageNumberPagination
 8 from .models import Goods
 9 
10 from rest_framework import viewsets
11 
12 
13 # Create your views here.
14 
15 
16 class GoodsPagination(PageNumberPagination):
17     """
18     配置分页规则
19     """
20     page_size = 10
21     page_size_query_param = 'page_size'
22     page_query_param="p"
23     max_page_size = 1000
24 
25 
26 class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
27     """
28     商品列表
29     """
30     queryset = Goods.objects.get_queryset().order_by('id')
31     serializer_class = GoodsSerializer
32     pagination_class = GoodsPagination

将urls.py改写为:

代码语言:javascript
复制
from django.urls import path,include
import xadmin
#
from django.views.static import serve
from MXshop.settings import MEDIA_ROOT
# from goods.views_base import GoodsListView

from rest_framework.documentation import include_docs_urls
from rest_framework.routers import DefaultRouter
from goods.views import GoodsListViewSet

router = DefaultRouter()
router.register(r'goods', GoodsListViewSet)



urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    path('ueditor/',include('DjangoUeditor.urls')),
    #配置上传文件的访问处理函数
    path('media/<path:path>',serve,{'document_root':MEDIA_ROOT}),

    path('docs',include_docs_urls(title='慕学生鲜')),
    path('api-auth/', include('rest_framework.urls',namespace='rest_framework')),
    path('',include(router.urls))
]

重启项目,访问:http://127.0.0.1:8000/goods 即可看到商品列表页

4.drf的request和response

request.data返回请求主体的解析内容,这与django本身的request.POST+request.FILES属性类似。不同之处:

  • 它包括所有解析的内容,包括文件和非文件输入。
  • 它支持解析HTTP方法以外的内容POST,这意味着你可以访问内容PUTPATCH请求。
  • 它支持REST框架的灵活请求解析,而不仅仅是支持表单数据。例如,您可以像处理传入表单数据一样处理传入的JSON数据。

request.query_params相当于django本身的request.GET。任何HTTP方法类型都可能包含查询参数,而不仅仅是GET请求。

parsers解析器,通过对应方法,解析传过来的各种类型数据。

5.drf的过滤

1.简单的过滤,改写一下views:

代码语言:javascript
复制
 1 from .serializer import GoodsSerializer
 2 from rest_framework.views import APIView
 3 from rest_framework.response import Response
 4 
 5 from rest_framework import mixins
 6 from rest_framework import generics
 7 from rest_framework.pagination import PageNumberPagination
 8 from .models import Goods
 9 
10 from rest_framework import viewsets
11 
12 
13 # Create your views here.
14 
15 
16 class GoodsPagination(PageNumberPagination):
17     """
18     配置分页规则
19     """
20     page_size = 10
21     page_size_query_param = 'page_size'
22     page_query_param="p"
23     max_page_size = 1000
24 
25 
26 class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
27     """
28     商品列表
29     """
30     # queryset = Goods.objects.get_queryset().order_by('id')
31     serializer_class = GoodsSerializer
32     pagination_class = GoodsPagination
33 
34     def get_queryset(self):
35         return Goods.objects.filter(shop_price__gt=100)

重启项目,访问:http://127.0.0.1:8000/goods 即可看到商品列表页中,过滤之后的数据。

2.自定义过滤器

在settings.py中注册django_filter,在末尾配置过滤

代码语言:javascript
复制
 1 INSTALLED_APPS = [
 2     .....
 3     'django_filters',
 4  
 5 ]
 6 
 7 ......
 8 
 9 REST_FRAMEWORK = {
10     # 分页显示
11     'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
12     'PAGE_SIZE': 10,
13     # 配置过滤
14     'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
15 }

在apps/goods下新建filter.py 文件:

代码语言:javascript
复制
 1 import django_filters
 2 from .models import Goods
 3 
 4 class GoodsFilter(django_filters.rest_framework.FilterSet):
 5     """商品过滤器"""
 6     price_min=django_filters.NumberFilter(name='shop_price',lookup_expr='gte')
 7     price_max = django_filters.NumberFilter(name='shop_price', lookup_expr='lte')
 8     #模糊查询,其中'contains'代表区分大小写,'icontains'代表不区分大小写
 9     name = django_filters.CharFilter(name='name', lookup_expr='icontains')
10     class Meta:
11         model=Goods
12         fields=['price_min','price_max','name']

在apps/goods/views中引用改写:

代码语言:javascript
复制
 1 ......
 2 
 3 from rest_framework import viewsets
 4 from django_filters.rest_framework import DjangoFilterBackend
 5 from .filter import GoodsFilter
 6 # Create your views here.
 7 
 8 ......
 9 class  GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
10     """
11     商品列表
12     """
13     queryset = Goods.objects.all()
14     serializer_class = GoodsSerializer
15     pagination_class = GoodsPagination
16     filter_backends = (DjangoFilterBackend,)
17     filter_class=GoodsFilter

效果图

6.drf的搜索和排序

1.搜索

apps/goods/views.py 内改写代码:

代码语言:javascript
复制
 1 .......
 2 from rest_framework import filters
 3 
 4 ......
 5 
 6 class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
 7     """
 8     商品列表
 9     """
10     queryset = Goods.objects.all()
11     serializer_class = GoodsSerializer
12     pagination_class = GoodsPagination
13     filter_backends = (DjangoFilterBackend,filters.SearchFilter)
14     filter_class=GoodsFilter
15     search_fields = ('name', 'goods_brief','goods_desc')

效果图

2.排序

apps/goods/views.py 内改写代码:

代码语言:javascript
复制
 1 .........
 2 from rest_framework import filters
 3 ...........
 4 
 5 ........
 6 
 7 class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
 8     """
 9     商品列表
10     """
11     queryset = Goods.objects.all()
12     serializer_class = GoodsSerializer
13     pagination_class = GoodsPagination
14     filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)
15     filter_class=GoodsFilter
16     search_fields = ('name', 'goods_brief','goods_desc')
17     ordering_fields=('sold_num','add_time')

效果图

 小结

我们通过viewsets和一个类,完成了商品列表页,分页,过滤,搜索,排序。

代码语言:javascript
复制
class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    """
    商品列表页,分页,过滤,搜索,排序
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)
    filter_class=GoodsFilter
    search_fields = ('name', 'goods_brief','goods_desc')
    ordering_fields=('sold_num','add_time')
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-03-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Django2.0的view实现商品列表页
    • 小贴士:怎样理解json?
    • 二、apiview方式实现商品列表页
      • 1.drf(Django REST framework)所需插件:
        •  2.实现商品列表页
          • 1.配置 rest_framework
          • 2.drf写views
      • 三、drf实现商品列表页的功能
        • 1.ModelSerializer(相当于django中的modelform,但是更加强大)
          • 2.使用mixins让代码变得更简洁
            • 1.精简apps/goods/views.py里面的代码后:
            • 2.drf分页
            • 3.最重要的viewsets和router(路由器)来实现商品列表页
            • 4.drf的request和response
            • 5.drf的过滤
            • 6.drf的搜索和排序
          •  小结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档