5- vue django restful framework 打造生鲜超市 -完成商品列表页(上)
使用Python3.6與Django2.0.2(Django-rest-framework)以及前端vue開發的前后端分離的商城網站
項目支持支付寶支付(暫不支持微信支付),支持手機短信驗證碼注冊, 支持第三方登錄。集成了sentry錯誤監控系統。
本小節內容: Django原生以及使用drf 完成 商品列表頁
django的view實現商品列表頁
本章節很重要。
通過Django的fbv cbv (class base view)都可以實現。
更建議通過基于class的view編碼,面向對象。
實現json返回。通過商品列表頁學習大多數drf知識點
查看Django的開發文檔可以看到提供了很多view來減少我們的代碼量
class GoodsListView(View): def get(self, request): """ 通過django的view實現商品列表頁 """ json_list = [] goods = Goods.objects.all()[:10] from django.forms.models import model_to_dict for good in goods: json_dict = model_to_dict(good) json_list.append(json_dict) import json from django.core import serializers json_data = serializers.serialize('json', goods) json_data = json.loads(json_data) from django.http import HttpResponse, JsonResponse return JsonResponse(json_data, safe=False)model_to_dict 將model轉換為字典,不用一個字段一個字段提取。
- images field和 datetime直接dumps會出錯
- serializers 專門用于序列化,有了這個序列化,其實上面的model_to_dict都不用做了
說明這是一個moudle我們不能直接調用,而應該進一步寫明調用其中哪個方法。
mark推薦閱讀:
https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00138683221577998e407bb309542d9b6a68d9276bc3dbe000
Django本身的實現其實已經蠻簡單了,那我們為啥要用drf
敲重點!!!
images這個圖片保存的是一個相對路徑,而我們需要加上前面的前綴。
這個工作drf可以完成補前綴工作。
字段序列化方式被定死了,重組麻煩。
文檔生成,輸入檢測(你是放在request body還表單過來的)
使用drf完成商品列表頁
商品列表頁過基礎知識
http://www.django-rest-framework.org/
強大的,靈活的,api
- Web browsable API
- Authentication policies 認證
- Serialization that supports both ORM and non-ORM data sources.
序列化ORM 和 非ORM的數據源
regular function-based views 我們是用的cbv
mark安裝
coreapi (1.32.0+) - Schema generation support. django-guardian (1.1.1+) - Object level permissions support.對象級別的權限支持,coreapi支持文檔
安裝時報出utf-8 decode錯誤
修改虛擬環境中的
D:\CodeSpace\PythonEnvs\mxshop36\Lib\site-packages\pip\compat大約75行
mark如果出現錯誤,把這個地方改為gbk
引入我們的文檔。
# 自動化文檔,1.11版本中注意此處前往不要加$符號path('docs/', include_docs_urls(title='mtianyan生鮮超市文檔'))配置好了只要運行不報錯驗證成功。
Add 'rest_framework' to your INSTALLED_APPS setting.
INSTALLED_APPS = (...'rest_framework', ) path('api-auth/', include('rest_framework.urls')) markhttp://www.django-rest-framework.org/tutorial/3-class-based-views/
這里面官方給出了一個例子如何簡單的寫一個class view
class SnippetList(APIView): """ List all snippets, or create a new snippet. """ def get(self, request, format=None): snippets = Snippet.objects.all() serializer = SnippetSerializer(snippets, many=True) return Response(serializer.data)將官方示例中的snippets用我們的Goods代替
mark可以看到api view也是繼承的view在它之上做了很多事。
from .models import Goods寫明引入當前目錄下models中的Goos不容易重名失敗。
可以自定義序列化的類。SnippetSerializer
modelform 和 form。modelform可以將字段直接轉成html
現在drf里的Serializer是用來取代form開發的。modelfrom是針對html的,
Serializer是針對json的。
和之前的form一樣。新建一個文件serializers.py
http://www.django-rest-framework.org/tutorial/1-serialization/
from rest_framework import serializersclass GoodsSerializer(serializers.Serializer): name = serializers.CharField(required=True,max_length=100) click_num = serializers.IntegerField(default=0)字段太多了。我們先講兩個。
mark因為我們是在用瀏覽器請求所以Drf會幫你渲染成網頁格式
mark這就是drf的Web browsable API
使用瀏覽器請求會返回html。
markget的時候指明json
mark mark接口的描述我們可以自行定義。
post過去的數據他能解析的格式。
因為我們是序列化的Goods,所以我們的Serializer要和goods model中保持一致
我們在Serializer中加上front image
mark可以看到我們返回的json中,image字段全部加上了media前綴
前綴是通過我們setting的MEDIA_URL 來自動添加的。
drf的modelSerializer實現商品列表頁功能
在drf的登錄系統中user nonetype
注意檢查這里需要返回的是username
之所以可以登錄退出,
是因為這里配置了一個url
goods/views.py添加:
def post(self, request, format=None): serializer = GoodsSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)接收前端request數據,交給GoodsSerializer進行驗證,驗證通過進行保存。
goods/serializers.py添加:
def create(self, validated_data): """ Create and return a new `Goods` instance, given the validated data. """ return Goods.objects.create(**validated_data)有了drf之后,他會把不管是用戶GET post Body過來的數據
都會取到,放到data中。不需要對于get post 等做單獨的處理。
save 會去調用Serializer里的create方法。
Django有form和modelform。那么Serializer是不是也有他的model
bingo
class GoodsSerializer(serializers.ModelSerializer): class Meta: model = Goods # fields = ('category', 'goods_sn', 'name', 'click_num', 'sold_num', 'market_price') fields = "__all__" mark外鍵會序列化成id。那我們通過id拿到對應的category
進行Serializer的嵌套使用。覆蓋外鍵字段
class CategorySerializer(serializers.ModelSerializer): class Meta: model = GoodsCategory fields = "__all__" class GoodsSerializer(serializers.ModelSerializer): category = CategorySerializer() class Meta: model = Goods # fields = ('category', 'goods_sn', 'name', 'click_num', 'sold_num', 'market_price') fields = "__all__"GenericView 方式實現商品列表頁和分頁功能
使用更加上層的view寫起來更簡單。
使用Using mixins 和 generic view
GenericAPIView是在apiview的基礎上加了filter 分頁等一堆東西
我們不用添加createModelMixin是因為我們的商品數據是后臺添加的,前臺不會提交。
class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView): """ 商品列表頁 """ queryset = Goods.objects.all() serializer_class = GoodsSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)list函數是在mixin中的,做了分頁以及序列化。
不去重寫定義get等http請求的方法默認你不接收這種方法
雖然上面已經很簡單了,但是我們能不能更簡單呢。
查看源碼路徑: D:/CodeSpace/PythonEnvs/mxshop36/Lib/site-packages/rest_framework
D:/CodeSpace/PythonEnvs/mxshop36/Lib/site-packages/rest_framework/generics.py
mark這些view都是官方提供給我們的view
- ListAPIview (獲取列表)
- CreateAPiView (創建一個)
- Retrieve (獲取某一條)
列表頁通常都是要分頁的,我們如何只通過setting的一個配置完成我們的分頁。
所有關于restframework的配置要寫在變量里
D:/CodeSpace/PythonEnvs/mxshop36/Lib/site-packages/rest_framework/settings.py
源碼中的setting配置
mark可以看到已經不提供默認的分頁類了。我們需要自己指明
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination','PAGE_SIZE': 10, } mark mark返回的數據有了變化。
有了count next頁的url,將之前的數據放到了results中
mark很神奇的是圖片連域名都加上了。
問題來了: 這個域名怎么加上的,待探究。
將整個url提供實際是我們restful api的一個標準
class GoodsPagination(PageNumberPagination): page_size = 12 page_size_query_param = 'page_size' page_query_param = "page" max_page_size = 100最多100個。
goodslistview中添加
pagination_class = GoodsPagination mark第幾頁,每一頁取多少條都變成了可配置的。
Viewsets和router完成商品列表頁
from rest_framework import viewsets mark可以看到它里面包含的
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):它的內部之間pass,只是多繼承了一個ViewSetMixin
ViewSetMixin中重寫了as_view方法可以讓我們的注冊url變得更加簡單
mark在view的基礎上設置了很多動作。動態設置Serializer
class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):GenericViewSet只繼承了api view,那么原來ListAPIView中的get方法的實現就沒有了
class GoodsListView(mixins.ListModelMixin, viewsets.GenericViewSet):ViewSets和Routers配套使用。
goods/views.py
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):改名字
配置我們的url
goods_list = GoodsListViewSet.as_view({'get': 'list', })將get請求綁定到list之上,類似于之前的
def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)這樣我們就不用自己再去綁定了。
配置url時就不用再加as_view()了
# 商品列表頁path('goods/', goods_list,name="goods-list"),但是我們可以更厲害一點,直接不用進行這個get 與list的綁定,它自動完成
我們要介紹的router就是做這個的。
from rest_framework.routers import DefaultRouterrouter = DefaultRouter()# 配置goods的url router.register(r'goods', GoodsListViewSet)url中配置
# router的path路徑re_path('^', include(router.urls)),router自動幫我們配置了get 和list,create 和 post的綁定
對于api view, GenericView viewset 和 router 的原理分析
理清我們的這些view他們之間的關系,以及listmodelMixin。
以及這些關系的組合使用,這樣才能讓我們更清楚什么時候使用哪種。
這些view之間的差異就引出了drf中另一個核心點mixin
mark可以看到源碼中的mixin一共有五種
而各種view的差異,mixin就扮演著重要的角色
以ListModelMixin為例做區別,如果我們不去繼承這個mixin它里面的這些方法的話。
就無法將get 和 list連接起來。無法連接,那么list中所作的所有功能都不能完成。
比如其中的
queryset = self.filter_queryset(self.get_queryset())page = self.paginate_queryset(queryset)if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)過濾,分頁都將享受不到。
RetrieveModelMixin對于具體的商品信息進行了獲取,序列化。這個在后面的商品詳情頁會介紹到。
UpdateModelMixin中對于部分更新還是全部更新進行了判斷。
DestroyModelMixin用來連接我們的delete方法,在我們delete時有一些必要的操作,如設置返回狀態204等。
上述這些功能都是mixin做的,而generic view并沒有做。所以drf是通過兩者的結合來實現。
GenericAPIView繼承于views.APIView
Base class for all other generic views.是所有通用視圖的基類
filter_backends = api_settings.DEFAULT_FILTER_BACKENDS pagination_class = api_settings.DEFAULT_PAGINATION_CLASS在原本的apiview基礎上添加了過濾,分頁。如果不用genericapiview而用api view這些事情都要我們自己實現。
配合著genericview 加上mixin就能組合出更加強大的:
mark如上圖這些分別為某個單獨操作設置的apiview
class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView): """ Concrete view for retrieving a model instance. 具體的視圖 對于 檢索一個model實例 """ def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs)get響應的是瀏覽器發過來的請求,瀏覽器發過來的請求只有http協議中規定的幾種。
我們將get請求綁定上retrieve方法,就能享受到retrieve方法給我們的好處
我們可以自己寫一個view來繼承mixins.RetrieveModelMixin,GenericAPIView 但是我們
一定要把get 和 retrieve的綁定寫上。
一般我們都會優先考慮下面組合好的這些apiview。還是滿足不了要求,那就自己組合,滿足這種配置方式就可以了。
Viewset有哪些好處?
generic下的各種變種view也是繼承了genericAPIView,配合各種mixin進行組合工作。
它將具體的單個modelmixin(如:mixins.RetrieveModelMixin,)換成了ViewSetMixin
之前我們需要寫函數將get等與retrieve等進行綁定。
ViewSetMixin的好處就是: 不需要我們通過方法來綁定。但是我們還是需要綁定關系的。
在url配置的時候進行綁定。
def as_view(cls, actions=None, **initkwargs)他重寫了as_view,接受參數,傳遞到對應的method 與 action進行綁定
goods_list = GoodsListViewSet.as_view({'get': 'list', })將本來在代碼中的綁定移到url中進行一個綁定的配置。
我們可以用router進行一個默認的綁定,router中的綁定其實和generic中的差不多
viewSetmixin還有一個很大的功能:
def initialize_request(self, request, *args, **kwargs): """ Set the `.action` attribute on the view, depending on the request method. """ request = super(ViewSetMixin, self).initialize_request(request, *args, **kwargs) method = request.method.lower() if method == 'options': # This is a special case as we always provide handling for the # options method in the base `View` class. # Unlike the other explicitly defined actions, 'metadata' is implicit. self.action = 'metadata' else: self.action = self.action_map.get(method) return request為視圖綁定動作,依賴于具體的request請求方法。這些action在我們后期進行動態Serializer時有很大好處。
mark
文章學習來自簡書 作者:天涯明月笙
原文鏈接:https://www.jianshu.com/p/6a6fa62d8152
轉載于:https://www.cnblogs.com/xinjie57/p/9144769.html
總結
以上是生活随笔為你收集整理的5- vue django restful framework 打造生鲜超市 -完成商品列表页(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python其他数据结构collecti
- 下一篇: urllib使用二