Django REST Framework Quickstart 項(xiàng)目解讀

初衷

在2018年5月份接觸并搭建過基于Django的后端平臺,由于當(dāng)時(shí)時(shí)間緊任務(wù)單一,很多細(xì)節(jié)也沒去深究。但是我清除地記著我是有去找過Django REST相關(guān)的解讀的,但是無果。最近有些時(shí)間,開始搭建一個(gè)較完整的基于Django的平臺,結(jié)果發(fā)現(xiàn)“毒”還在,看來只能自制“解藥”了。因?yàn)殡x上一次寫類似博客的東西已經(jīng)很久了,所以語言組織已經(jīng)退化,不求寫清楚了,但求和我一樣的入門者有一個(gè)可聊的話題。

創(chuàng)建工程,添加一個(gè)應(yīng)用

  • 基于virtualenv創(chuàng)建工作環(huán)境,遠(yuǎn)離python版本管理的煩惱
virtualenv -p /usr/local/bin/python3 py3env
source py3env/bin/activate
pip install django
pip install djangorestframework
  • 創(chuàng)建工程和應(yīng)用
django-admin.py startproject tutorial .
cd tutorial
django-admin.py startapp quickstart
  • 默認(rèn)使用sql數(shù)據(jù)庫初始化數(shù)據(jù)庫設(shè)置
python manage.py migrate
  • 創(chuàng)建管理員賬號
python manage.py createsuperuser

關(guān)于Quickstart

這是一個(gè)官方的demo:http://www.django-rest-framework.org/tutorial/quickstart/, 目的是為了向開發(fā)者展示該組件的易用性,但是立足點(diǎn)似乎有點(diǎn)高,作為剛剛開始接觸Django并想要了解REST組件的同學(xué)來說,這個(gè)例子的文檔比較晦澀,而且絕大部分資料也只是對官方文檔的翻譯。該demo的功能,是實(shí)現(xiàn)一套簡單的api(含視圖),用于管理員查看和編輯Django的用戶和組信息。

了解流程

由于Django本身是MVC(MVT)結(jié)構(gòu),便于開發(fā),但不便于入門理解,簡單地說,就是不便于在入門時(shí)理解Demo代碼中的關(guān)聯(lián)性。

  • Django的MTV模塊

    • M:負(fù)責(zé)業(yè)務(wù)和數(shù)據(jù)庫的關(guān)系映射
    • T:負(fù)責(zé)如何把html頁面展示給用戶
    • V:負(fù)責(zé)業(yè)務(wù)邏輯,調(diào)用M和T(MVC中C的角色)
  • Django對請求的處理流程并不是僅僅MTV三個(gè)模塊

    Django處理流程

    其實(shí)從WSGI以后,都算作Django的工作范圍,WSGI通過調(diào)用Django中的Django.core.wsgi的入口方法(wgsi.py文件)以后,就將請求的數(shù)據(jù)結(jié)構(gòu)傳遞給Django的各種中間件,具體會流經(jīng)哪些中間件?可見setting.py中的MIDDLEWARE配置(跨域過濾之類的一般會設(shè)置在中間件中)

  • Django app內(nèi)部的流程會相對清晰一些:

    • URLconf是指urls.py選擇一個(gè)視圖來處理請求
    • 被選擇的那個(gè)視圖通常要做下面所列出的一件或者更多件事情:
      • 通過model與數(shù)據(jù)庫對話
      • 使用模板渲染HTML或者任何格式化過的響應(yīng)
      • 返回一個(gè)純文本響應(yīng)(不被顯示的)(API)
    • 返回response

額外的重點(diǎn):序列化

序列化和反序列化的目的就是對象和傳輸數(shù)據(jù)(或是存儲數(shù)據(jù))之間的轉(zhuǎn)換。Django本身和Django REST 組件都提供了序列化的輔助類,目的是為了簡化代碼(可以想象一下JAVA里的序列化操作,雖然有工具可以生成代碼),特別是ModelForm、ModelSerializer這些類,可以通過直接連接model模塊,完成序列化和反序列化的工作。序列化功能的實(shí)現(xiàn),往往是實(shí)現(xiàn)功能的第一步。我們可以理解成數(shù)據(jù)流驅(qū)動(dòng)了編碼順序。

  • 序列化:對象 -> 字節(jié)序列(數(shù)據(jù)庫或者response)
  • 反序列化:字節(jié)序列 -> 對象
    從上面的描述上看,序列化功能類一般會用在連接model、return response,以及數(shù)據(jù)庫操作上。

再看Demo代碼

1、真正的第一步應(yīng)該是設(shè)計(jì)并建立數(shù)據(jù)庫,而demo是要實(shí)現(xiàn)項(xiàng)目用戶的操作,使用了自帶的用戶信息所在數(shù)據(jù)庫。
2、實(shí)現(xiàn)序列化功能
在知道后端有什么(數(shù)據(jù)庫),前端要什么之后,我們就可以設(shè)計(jì)序列化功能。因?yàn)閿?shù)據(jù)庫有什么我們就可以知道應(yīng)該反序列出來什么,前端要什么,我們就知道需要序列化到response什么內(nèi)容了。
Django提供了通用的serializers、ModelSerializer、HyperlinkedModelSerializer等封裝等級不同和類型不同的序列化器輔助類,唯一的區(qū)別就是簡化代碼的程度不同,如果對序列化的具體操作不熟悉的話,可以參照https://darkcooking.gitbooks.io/django-rest-framework-cn/content/chapter1.html 使用普通的serializers來實(shí)現(xiàn)一遍該類會幫助很大。

from django.contrib.auth.models import User, Group
from rest_framework import serializers


class UserSerializer(serializers.HyperlinkedModelSerializer):

    """
    用戶信息的序列化器(根據(jù)前端需要的數(shù)據(jù)信息來組織結(jié)構(gòu))
    """
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups')


class GroupSerializer(serializers.HyperlinkedModelSerializer):

    """
    組信息的序列化器
    """
    class Meta:
        model = Group
        fields = ('url', 'name')

3、實(shí)現(xiàn)View
這個(gè)Demo變得晦澀難懂的一大原因就是直接用了最簡潔的代碼方式,這里的viewsets就是其中之一,包括上面HyperlinkedModelSerializer。差別之處可以參考:https://darkcooking.gitbooks.io/django-rest-framework-cn/content/chapter6.html

"""
View中,必然會看到model(操作數(shù)據(jù)庫)和序列化器(組織response內(nèi)容)
"""
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from quickstart.serializers import UserSerializer, GroupSerializer


class UserViewSet(viewsets.ModelViewSet):

    """
    處理查看、編輯用戶的界面
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer


class GroupViewSet(viewsets.ModelViewSet):

    """
    處理查看、編輯用戶組的界面
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

為了理解這些晦澀的用法,還是總結(jié)下,Django Rest對視圖寫法的精簡可以一步步歸納為:

  • 1、使用常規(guī)方式實(shí)現(xiàn),最顯式的實(shí)現(xiàn)方式,也是最好理解的方式:(讀取數(shù)據(jù)庫字節(jié)序列->反序列化->序列化后response)
@csrf_exempt
def snippet_list(request):
    """
    展示所以snippets,或創(chuàng)建新的snippet.
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return JSONResponse(serializer.data)
    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JSONResponse(serializer.data, status=201)
        return JSONResponse(serializer.errors, status=400)
  • 2、使用基于函數(shù)視圖的@api_view裝飾器,加快實(shí)現(xiàn)
@api_view(['GET', 'POST'])
def snippet_list(request):
    """
    展示或創(chuàng)建snippets.
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)
    elif request.method == 'POST':
        serializer = SnippetSerializer(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)
  • 3、使用基于類視圖的APIView
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)
    def post(self, request, format=None):
        serializer = SnippetSerializer(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)
  • 4、基于ViewSets的抽象行為(配合Routers實(shí)現(xiàn)),該方法也可以簡化urlconf,所以這可能就是Django生態(tài)的好處,讓我們更加關(guān)注api的交互,但是這之前還是需要清楚這些方法的演變過程。從這個(gè)角度上看,讀了N遍官方文檔之后,能發(fā)現(xiàn)官方真正想要傳達(dá)的意思。
class SnippetViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.
    Additionally we also provide an extra `highlight` action.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)
    @detail_route(renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)
    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

4、實(shí)現(xiàn)urlpatterns

使用viewsets和router后,由于封裝處理了“get”、“post” 等默認(rèn)動(dòng)作,所以在url.py指出特定的uri便可,這就是所謂的RESTFul,因?yàn)樗械摹皠?dòng)作”都沒有暴露到api的命名中。

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from rest_framework import routers
from quickstart import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)

# 使用URL路由來管理我們的API
# 另外添加登錄相關(guān)的URL
urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('admin/', admin.site.urls),
]

5、運(yùn)行測試。

python manage.py runserver

便可看到一套自帶界面的api,一開始可能會有疑問,說好是寫一套apis的,怎么成了一個(gè)界面了,其實(shí)就是Django MTV的福利(自帶doc有沒有),大家試著去訪問:http://127.0.0.1:8000/users/?format=json ,就能看到一個(gè)正常的接口返回了。

運(yùn)行結(jié)果

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明AGI閱讀 16,018評論 3 119
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 聽完永澄老師第三章的解讀,有如下收獲。 一、通過結(jié)構(gòu)的重新梳理,內(nèi)容理解更為透徹 我在學(xué)習(xí)時(shí),自己做的筆記,就是一...
    從零再次起步閱讀 247評論 0 1
  • 你才二十多歲,沒有遇到喜歡的人很正常,越往后你會發(fā)現(xiàn),大概是遇不到了。突然覺得十幾二十歲還沒有遇到愛的人很不正常,...
    嬙嬙99加閱讀 219評論 0 0
  • 周一: 6:00 鬧鈴響了,迷糊10鐘,起床。 6:40 吃早飯 7:20 做早操 7:40 整理寢室 8:30 ...
    裊雨閱讀 106評論 0 0