欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

(项目)生鲜超市(四)

程序员文章站 2022-06-08 20:39:56
五、商品列表页面 1、Django的view实现商品列表页面 为了区分django的view和django rest framework的view,在goods下面新建view_base.py文件,该项目采用前后端分离,所以和模板技术不一样返回的是模本文件,现在给前端返回的必须是json数据: 配置 ......

五、商品列表页面

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')

(项目)生鲜超市(四)