zoukankan      html  css  js  c++  java
  • 04-商品列表页

    一、前后端分离优缺点

    优点:

      1、由于pc、app、pad多端适应  2SPA开发模式开始流行 3、前后端开发职责不清 4、开发效率问题,前后端相互等待 5、前端一直配合后端,能力有限 6、后台开发语言和模板高度耦合

    缺点:

      1、前后端学习门槛增加 2、数据依赖,导致文档的重要性增加 3、前端工作量增加 4SEO的难度加大(搜索引擎优化) 5、后端模式迁移成本增加

    restful api

      restful api是前后端分离目前来说是最佳实践,开发的标准规范,不是框架,是一种标准规范。优点就是轻量,直接通过http,不需要额外的协议,post/get/put/delete/patch/操作,同时还是面向资源,一目了然,具有解释性。第三就是数据描述简单,一般通过json或者xml做数据通信。每一个URI代表一种资源,客户端和服务器之间,传递这种资源的某种表现层,客户端通过五个HTTP动词,对服务器资源进行操作,实现表现层状态转化。

    1、Django的View实现商品列表页

      为了更好的理解restful apiDjango原来的工作流程,我们在应用中新建一个views_base视图,然后写我们的逻辑。

    Mxshop/urls.py

    """MxShop URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/2.2/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    # from django.contrib import admin
    from django.urls import path,re_path
    #将设置里的media路径导入进来进行配置,还有用到静态文件的serve方法
    from MxShop.settings import MEDIA_ROOT
    from django.views.static import serve
    import xadmin
    
    from goods.views_base import GoodsListView
    
    urlpatterns = [
        path('xadmin/', xadmin.site.urls),
        #用正则匹配media路径下的文件进行访问
        re_path('media/(?P<path>.*)$',serve,{"document_root":MEDIA_ROOT}),
        path('goods/',GoodsListView.as_view(),name="goods_list")
    ]

    goods/views_base.py:

    __author__ = "lishuntao"
    __date__ = "2019/11/15 0015 12:26"
    
    import json
    from django.views.generic.base import View #CBV模式最常用也是最底层的View
    # from django.views.generic import ListView  #和上面一样
    from django.http import HttpResponse
    
    from goods.models import Goods
    
    
    class GoodsListView(View):
        def get(self,request):
            """
            通过Django的View实现商品列表页
            :param request:
            :return:返回一个json格式的数据
            """
            json_list = []
            goods = Goods.objects.all()[:10]
            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)
            return HttpResponse(json.dumps(json_list),content_type="application/json")

    然后启动项目,去浏览器中访问

     

     

     

       数据自动转换为开发者模式,这样是不是方便多了啊。但这样编写视图,每次查询列表页,每次都要将模型类的字段赋值,这样是不是很不方便,甚至多了繁杂还容易出错,那有没有什么办法,我们开发者不用写这些繁琐的简单代码,让一种工具自动帮我们转换为dict格式,django.forms.models import model_to_dict就可以帮我们完成这个繁琐工作。

    改动后的代码

    import json
    from django.views.generic.base import View #CBV模式最常用也是最底层的View
    # from django.views.generic import ListView  #和上面一样
    from django.http import HttpResponse
    
    from goods.models import Goods
    
    
    class GoodsListView(View):
        def get(self,request):
            """
            通过Django的View实现商品列表页
            :param request:
            :return:返回一个json格式的数据
            """
            json_list = []
            goods = Goods.objects.all()[:10]
            # 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)
            #这下面的Django提供的方法model_to_dict 就是将模型类的字段,转换为dict形式
            from django.forms.models import model_to_dict
    for good in goods: json_dict = model_to_dict(good) json_list.append(json_dict) return HttpResponse(json.dumps(json_list),content_type="application/json")

    启动项目,访问发现图片不能被序列化,除此之外,时间类型字段也不能被序列化。

     有一个django提供的可以将这些不能被序列化的字段序列化,django.core import serializers:

    __author__ = "lishuntao"
    __date__ = "2019/11/15 0015 12:26"
    
    import json
    from django.views.generic.base import View #CBV模式最常用也是最底层的View
    # from django.views.generic import ListView  #和上面一样
    from django.http import HttpResponse
    
    from goods.models import Goods
    
    
    class GoodsListView(View):
        def get(self,request):
            """
            通过Django的View实现商品列表页
            :param request:
            :return:返回一个json格式的数据
            """
            json_list = []
            goods = Goods.objects.all()[:10]
            # 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)
            #这下面的Django提供的方法model_to_dict 就是将模型类的字段,转换为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.core import serializers
            json_data = serializers.serialize("json",goods)
            json_data = json.loads(json_data)
    
            return HttpResponse(json_data,content_type="application/json")
    View Code

     可以发现,启动说的是在第一行解析错误,这是因为上面发送回客户端的数据必须,一定是json.dumps的数据,否则的话,就会解析错误。

    __author__ = "lishuntao"
    __date__ = "2019/11/15 0015 12:26"
    
    import json
    from django.views.generic.base import View #CBV模式最常用也是最底层的View
    # from django.views.generic import ListView  #和上面一样
    from django.http import HttpResponse
    
    from goods.models import Goods
    
    
    class GoodsListView(View):
        def get(self,request):
            """
            通过Django的View实现商品列表页
            :param request:
            :return:返回一个json格式的数据
            """
            json_list = []
            goods = Goods.objects.all()[:10]
            # 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)
            #这下面的Django提供的方法model_to_dict 就是将模型类的字段,转换为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.core import serializers
            json_data = serializers.serialize("json",goods)
            json_data = json.loads(json_data)#序列化的数据一定是先反序列化后,发送回客户端在序列化发送
    
            return HttpResponse(json.dumps(json_data),content_type="application/json")
    View Code

    当然,被json_data = serializers.serialize("json",goods)的返回值json_data数据直接就可以返回客户端,因为他已经自动帮我们把数据json.dumps啦,还有一种就是这里将不再演示。

     刚才报错的图片和时间,都能够正常解析啦。(下面的是第二种django.http提供了json格式的返回,更加方便,只需要数据是一个字典格式即可)

    2、APIView的方式实现商品列表页的功能(需要用到DRF所以去官方文档查看)

     APIView使用前的配置,首先到项目路由urls.py下配置,否则以后引用APIView报错:

    """MxShop URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/2.2/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    # from django.contrib import admin
    import xadmin
    from django.urls import path,re_path
    #将设置里的media路径导入进来进行配置,还有用到静态文件的serve方法
    from MxShop.settings import MEDIA_ROOT
    from django.views.static import serve
    from rest_framework.documentation import include_docs_urls
    
    from goods.views_base import GoodsListView
    
    urlpatterns = [
        path('xadmin/', xadmin.site.urls),
        #用正则匹配media路径下的文件进行访问
        re_path('media/(?P<path>.*)$',serve,{"document_root":MEDIA_ROOT}),
        path('goods/',GoodsListView.as_view(),name="goods_list"),
        path('docs/',include_docs_urls(title="天天生鲜")),
    ]
    APIView使用前配置

    根据官方文档,让配置INSTALLED_APPS中注册rest_framework

     

     第二步官方文档要求注册这个路由,根据django版本配置urls.py

    """MxShop URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/2.2/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    # from django.contrib import admin
    import xadmin
    from django.urls import path,re_path,include
    #将设置里的media路径导入进来进行配置,还有用到静态文件的serve方法
    from MxShop.settings import MEDIA_ROOT
    from django.views.static import serve
    from rest_framework.documentation import include_docs_urls
    
    from goods.views_base import GoodsListView
    
    urlpatterns = [
        path('xadmin/', xadmin.site.urls),
        path('api-auth/', include('rest_framework.urls')),
        #用正则匹配media路径下的文件进行访问
        re_path('media/(?P<path>.*)$',serve,{"document_root":MEDIA_ROOT}),
        path('goods/',GoodsListView.as_view(),name="goods_list"),
        path('docs/',include_docs_urls(title="天天生鲜")),
    ]
    View Code

    注册好路由之后,这样就可以使用DRF的功能啦,首先要实现的是商品列表页功能,在Goods下的views.py中实现代码

    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    from .models import Goods
    from .serializers import GoodsSerializer
    
    # Create your views here.
    
    
    class GoodsList(APIView):
        """
        商品列表页
        """
        def get(self,request,format=None):
            goods = Goods.objects.all()[:10]
            #自定义的序列化器(goods.serializers中)
            goods_serializer = GoodsSerializer(goods,many=True)
            return Response(goods_serializer.data)

    视图中的GoodsSerializer类是自定义的序列化器,继承了DRFserializers.Serializer。实现其中两个字段来理解他的功能,则serializers.py的代码为:

    from rest_framework import serializers
    
    
    class GoodsSerializer(serializers.Serializer):
        name = serializers.CharField(default="",max_length=20)
        click_num = serializers.IntegerField(default=0,)

    配置路由(urls.py):

    from goods.views import GoodsList
    
    
    urlpatterns = [
        path('xadmin/', xadmin.site.urls),
        path('api-auth/', include('rest_framework.urls')),
        #用正则匹配media路径下的文件进行访问
        re_path('media/(?P<path>.*)$',serve,{"document_root":MEDIA_ROOT}),
        path('goods/',GoodsList.as_view(),name="goods_list"),
        path('docs/',include_docs_urls(title="天天生鲜")),
    ]

    启动访问的结果:

     

     继承Serializers.Serializer的类有create方法,重写这个方法,这是对模型类数据的创建:

        def create(self, validated_data):
            """
            创建一个Goods对象,
            :param validated_data:
            :return: 这个将数据保存到数据库
            """
            return Goods.objects.create(**validated_data)

    然后到视图函数中保存:

        def post(self,request):
            """
            保存数据
            :param request:
            :return:
            """
            serializer = GoodsSerializer(data=request.data)
            if serializer.is_valid():
                #在GoodsSerializer中调用模型类的create方法,然后在这里逻辑保存
                serializer.save()
                return Response(serializer.data,status=status.HTTP_201_CREATED)
            return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)

      继承APIView的序列化器是不是和Django.forms很像,都是可以对数据进行验证,然后进行相关逻辑操作。forms.Model可以对数据模型类进行保存,序列化器也有modelserializer,将serializer的方法都实现了,这样用起来更简单,实现起来更方便。

    ModelSerializer

    一运行,浏览器访问,然后就能看见外键的详细数据,并且还能直接将原来复杂得直接简写,功能强大。

    3、GenericView实现商品列表页和分页

    第一去项目设置里面添加REST_FRAMEWORK设置:

    REST_FRAMEWORK = {
        'PAGE_SIZE': 10,
    }

     自定义分类:

    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from rest_framework import mixins
    from rest_framework import generics
    from rest_framework.pagination import PageNumberPagination
    
    from .models import Goods
    from .serializers import GoodsSerializer
    
    # Create your views here.
    
    class GoodsSetPagination(PageNumberPagination):
        """
        定制分页设置
        """
        page_size = 1
        page_size_query_param = 'page_size'
        page_query_param = "p"
        max_page_size = 10000
    
    
    #GenericAPIView,对APIView进行一层封装,APIView是对View进行一层封装
    class GoodsList(generics.ListAPIView):
        """
        商品列表页,继承第一个是为了列表页,还要必须继承一个视图类
        ListAPIView已经将下面的代码完成
        """
        queryset = Goods.objects.all()
        serializer_class = GoodsSerializer
        pagination_class = GoodsSetPagination

     4、viewsets和router完成商品列表页(所有的API基本上都会用Viewset完成)

    views.py:

    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from rest_framework import mixins
    from rest_framework import generics
    from rest_framework.pagination import PageNumberPagination
    from rest_framework import viewsets
    
    from .models import Goods
    from .serializers import GoodsSerializer
    
    # Create your views here.
    
    class GoodsSetPagination(PageNumberPagination):
        """
        定制分页设置
        """
        page_size = 1
        page_size_query_param = 'page_size'
        page_query_param = "p"
        max_page_size = 10000
    
    
    #GenericAPIView,对APIView进行一层封装,APIView是对View进行一层封装
    class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
        """
        商品列表页
        """
        queryset = Goods.objects.all()
        serializer_class = GoodsSerializer
        pagination_class = GoodsSetPagination

    urls.py:

    """MxShop URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/2.2/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    # from django.contrib import admin
    import xadmin
    from django.urls import path,re_path,include
    #将设置里的media路径导入进来进行配置,还有用到静态文件的serve方法
    from MxShop.settings import MEDIA_ROOT
    from django.views.static import serve
    from rest_framework.documentation import include_docs_urls
    from rest_framework.routers import DefaultRouter
    
    from goods.views_base import GoodsListView
    from goods.views import GoodsListViewSet
    
    router = DefaultRouter()
    
    #配置goods的url
    router.register(r"goods",GoodsListViewSet)
    
    # goods_list = GoodsListViewSet.as_view({
    #     "get":"list",
    #     #DRF提供了router来配置这个路由
    # })
    
    urlpatterns = [
        path('xadmin/', xadmin.site.urls),
        path('api-auth/', include('rest_framework.urls')),
        #用正则匹配media路径下的文件进行访问
        re_path('media/(?P<path>.*)$',serve,{"document_root":MEDIA_ROOT}),
        # path('goods/',goods_list,name="goods_list"),
        re_path('^',include(router.urls)),
        path('docs/',include_docs_urls(title="天天生鲜")),
    ]
    urls.py

     5、DRF的过滤

    在应用下新建自定义的过滤,可以实现模糊查询等。

    import django_filters
    from .models import Goods
    
    
    class GoodsFilter(django_filters.rest_framework.FilterSet):
        """
        商品过滤器
        """
        price_min = django_filters.NumberFilter(field_name="shop_price",lookup_expr="gte")
        price_max = django_filters.NumberFilter(field_name="shop_price", lookup_expr="lte")
        name = django_filters.CharFilter(field_name="name", lookup_expr="icontains")
    
        class Meta:
            model = Goods
            fields = ["price_min","price_max","name"]
    goods/filters.py

    在设置里面添加django_filtersDjango中也可以自定义过滤

    INSTALLED_APPS = [
        'django.contrib.auth',
        'django.contrib.admin',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'users.apps.UsersConfig',
        'goods.apps.GoodsConfig',
        'trade.apps.TradeConfig',
        'user_operation.apps.UserOperationConfig',
        'DjangoUeditor',
        'xadmin',
        'crispy_forms',#这个是xadmin需要使用的
        'rest_framework',
        'django_filters',
    ]
    seetings.py

    在视图中的代码逻辑为

    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from rest_framework import mixins
    from rest_framework import generics
    from rest_framework.pagination import PageNumberPagination
    from rest_framework import viewsets
    from django_filters.rest_framework import DjangoFilterBackend
    
    from .models import Goods
    from .serializers import GoodsSerializer
    from .filters import GoodsFilter
    
    # Create your views here.
    
    class GoodsSetPagination(PageNumberPagination):
        """
        定制分页设置
        """
        page_size = 10
        page_size_query_param = 'page_size'
        page_query_param = "p"
        max_page_size = 10000
    
    
    #GenericAPIView,对APIView进行一层封装,APIView是对View进行一层封装
    class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
        """
        商品列表页
        """
        queryset = Goods.objects.all()
        serializer_class = GoodsSerializer
        pagination_class = GoodsSetPagination
        filter_backends = [DjangoFilterBackend]
        #这是精确搜索过滤,我们需要的是模糊搜索
        # filterset_fields = ['name', 'shop_price']
        filter_class = GoodsFilter
    views.py

    运行结果是:

     6、DRF的搜索和排序

    views.py中的逻辑代码(搜索):

    from rest_framework import filters
    
    
    class GoodsSetPagination(PageNumberPagination):
        """
        定制分页设置
        """
        page_size = 10
        page_size_query_param = 'page_size'
        page_query_param = "p"
        max_page_size = 10000
    
    
    #GenericAPIView,对APIView进行一层封装,APIView是对View进行一层封装
    class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
        """
        商品列表页
        """
        queryset = Goods.objects.all()
        serializer_class = GoodsSerializer
        pagination_class = GoodsSetPagination
        filter_backends = [DjangoFilterBackend,filters.SearchFilter]
        #这是精确搜索过滤,我们需要的是模糊搜索
        # filterset_fields = ['name', 'shop_price']
        filter_class = GoodsFilter
        search_fields = ("name","goods_brief","goods_desc")
    View Code

     排序:

    class GoodsSetPagination(PageNumberPagination):
        """
        定制分页设置
        """
        page_size = 10
        page_size_query_param = 'page_size'
        page_query_param = "p"
        max_page_size = 10000
    
    
    #GenericAPIView,对APIView进行一层封装,APIView是对View进行一层封装
    class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
        """
        商品列表页 分页 搜索 过滤 排序
        """
        queryset = Goods.objects.all()
        serializer_class = GoodsSerializer
        pagination_class = GoodsSetPagination
        filter_backends = [DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter]
        #这是精确搜索过滤,我们需要的是模糊搜索
        # filterset_fields = ['name', 'shop_price']
        filter_class = GoodsFilter
        search_fields = ("name","goods_brief","goods_desc")
        ordering_fields = ("shop_price","sold_num","add_time")
    排序

      总结DRF:首先我们通过创建views_base.py里面用Django的View来实现商品列表页,刚开始是自己序列化,然后通过介绍Django提供的方法model_to_dict,最后到使用Django原生的serializers以及使用它的JsonResponse的序列化,通过这些繁琐的工作,引出了DRF功能,首先通过APIView来完成,然后通过generics中的genericAPIView来实现了商品列表页,一直到最后使用ViewSets的东西来完成我们的商品列表页

  • 相关阅读:
    Java SPI机制详解
    ElasticSearch核心概念和原理
    多线程基础-线程创建、线程方法、线程状态等
    MyBatis-日志、分页、一对多or多对一
    MyBatis-注解开发、XML全局配置
    SpringMVC-数据输出、Map、Model、视图解析、处理Json
    SpringMVC-@RequestMapping、@PathVariable、Rest、POJO封装、乱码问题
    lazy loading img 图片延迟加载
    google 地图,多个标记 js库
    Jquery各版本下载,附Jquery官网下载方法
  • 原文地址:https://www.cnblogs.com/lishuntao/p/11867127.html
Copyright © 2011-2022 走看看