優勢:前端
1、因爲pc、app、pad多端適應 2、SPA開發模式開始流行 3、先後端開發職責不清 4、開發效率問題,先後端相互等待 5、前端一直配合後端,能力有限 6、後臺開發語言和模板高度耦合數據庫
缺點:django
1、先後端學習門檻增長 2、數據依賴,致使文檔的重要性增長 3、前端工做量增長 4、SEO的難度加大(搜索引擎優化) 5、後端模式遷移成本增長json
restful api後端
restful api是先後端分離目前來講是最佳實踐,開發的標準規範,不是框架,是一種標準規範。優勢就是輕量,直接經過http,不須要額外的協議,post/get/put/delete/patch/操做,同時仍是面向資源,一目瞭然,具備解釋性。第三就是數據描述簡單,通常經過json或者xml作數據通訊。每個URI表明一種資源,客戶端和服務器之間,傳遞這種資源的某種表現層,客戶端經過五個HTTP動詞,對服務器資源進行操做,實現表現層狀態轉化。api
一、Django的View實現商品列表頁瀏覽器
爲了更好的理解restful api與Django原來的工做流程,咱們在應用中新建一個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")
能夠發現,啓動說的是在第一行解析錯誤,這是由於上面發送回客戶端的數據必須,必定是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")
固然,被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="每天生鮮")), ]
根據官方文檔,讓配置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="每天生鮮")), ]
註冊好路由以後,這樣就可使用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類是自定義的序列化器,繼承了DRF的serializers.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的方法都實現了,這樣用起來更簡單,實現起來更方便。
一運行,瀏覽器訪問,而後就能看見外鍵的詳細數據,而且還能直接將原來複雜得直接簡寫,功能強大。
三、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="每天生鮮")), ]
五、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"]
在設置裏面添加django_filters在Django中也能夠自定義過濾
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', ]
在視圖中的代碼邏輯爲
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
運行結果是:
六、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")
排序:
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的東西來完成咱們的商品列表頁