04-商品列表頁

1、先後端分離優缺點

優勢:前端

  1、因爲pc、app、pad多端適應  2SPA開發模式開始流行 3、先後端開發職責不清 4、開發效率問題,先後端相互等待 5、前端一直配合後端,能力有限 6、後臺開發語言和模板高度耦合數據庫

缺點:django

  1、先後端學習門檻增長 2、數據依賴,致使文檔的重要性增長 3、前端工做量增長 4SEO的難度加大(搜索引擎優化) 5、後端模式遷移成本增長json

restful api後端

  restful api是先後端分離目前來講是最佳實踐,開發的標準規範,不是框架,是一種標準規範。優勢就是輕量,直接經過http,不須要額外的協議,post/get/put/delete/patch/操做,同時仍是面向資源,一目瞭然,具備解釋性。第三就是數據描述簡單,通常經過json或者xml作數據通訊。每個URI表明一種資源,客戶端和服務器之間,傳遞這種資源的某種表現層,客戶端經過五個HTTP動詞,對服務器資源進行操做,實現表現層狀態轉化。api

一、Django的View實現商品列表頁瀏覽器

  爲了更好的理解restful apiDjango原來的工做流程,咱們在應用中新建一個views_base視圖,而後寫咱們的邏輯。服務器

Mxshop/urls.pyrestful

"""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:session

__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格式的返回,更加方便,只須要數據是一個字典格式便可)

 

二、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

一運行,瀏覽器訪問,而後就能看見外鍵的詳細數據,而且還能直接將原來複雜得直接簡寫,功能強大。

三、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

 

 四、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

 五、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

運行結果是:

 

 六、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的東西來完成咱們的商品列表頁

相關文章
相關標籤/搜索