当前位置: 移动技术网 > IT编程>脚本编程>Python > (项目)生鲜超市(四)

(项目)生鲜超市(四)

2018年11月26日  | 移动技术网IT编程  | 我要评论

常州区号,海扁虫,歼敌机

五、商品列表页面

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

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网