Django API 服務(wù)器實(shí)現(xiàn) (Django_REST_framework)

上一章講解 《這絕對(duì)不是只是Django入門》 后,本該講解admin及web網(wǎng)頁等相關(guān)內(nèi)容,考慮是否應(yīng)該先插入《Django API 服務(wù)器實(shí)現(xiàn) 》因?yàn)檫@個(gè)實(shí)現(xiàn)簡單不需要掌握前端知識(shí)就可以實(shí)現(xiàn)。

Django中有一個(gè)框架django_REST_framework。本來想根據(jù)官方網(wǎng)站的目錄為大家一一講解,但是發(fā)現(xiàn)每一章都在為上一章而優(yōu)化。如需知道更詳細(xì)過程??梢匀ス俜骄W(wǎng)查看說明文檔django-rest-framework官方網(wǎng) 在講解 django_REST_framework 之前需要了解什么是RESTful。

RESTful(簡稱:REST ,英文為:Representational State Transfer)
描述了一個(gè)架構(gòu)樣式的網(wǎng)絡(luò)系統(tǒng),是指一組架構(gòu)約束條件和原則,這是一種軟件架構(gòu)風(fēng)格而不是強(qiáng)制(標(biāo)準(zhǔn))。提供了一組設(shè)計(jì)原則和約束條件。它用于客戶端和服務(wù)器交互的軟件。由于服務(wù)器與客戶端之間的交互請(qǐng)求是無狀態(tài)。

原本打算用一到兩天的時(shí)間來學(xué)習(xí)這個(gè)框架,后來發(fā)現(xiàn)真的是 too young too simple,很多實(shí)現(xiàn)方式是框架約定好的,在一個(gè)新手如果未了解根本無從下手。為了讓大家更好的看懂本章內(nèi)容,花了很多時(shí)間在整理,語言表達(dá)上。希望大家學(xué)完可以運(yùn)用在自己項(xiàng)目中。

django_REST_framework

執(zhí)行pip命令安裝框架

pip install djangorestframework

安裝成功后打開之前編輯中的項(xiàng)目,如果還沒編輯請(qǐng)參考 《這絕對(duì)不是只是Django入門》 創(chuàng)建一個(gè)django項(xiàng)目。
打開settings文件,把django_REST_framework框架導(dǎo)入到settings中,偷懶了一下借用個(gè)官方文檔中的案例為大家講解一下。同時(shí)如果有什么不明白的

python manage.py startapp snippets
# settings.py
# 注意安裝的時(shí)候djangorestframework 但導(dǎo)入是rest_framework,請(qǐng)不要寫錯(cuò)
import rest_framework   

INSTALLED_APPS = [
          ...
    'rest_framework',
    'snippets',
]

打開snippets目錄下的 models.py 文件,我們編寫該模型的類

# models.py
from __future__ import unicode_literals
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())

class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)

    class Meta:
        ordering = ('created',)  #根據(jù)created這個(gè)字段排序

這個(gè)類應(yīng)該很容易理解,我就不贅述了。如果有什么不明白的可以在django.db.models這個(gè)py文件查看源碼。

前面的準(zhǔn)備工作已經(jīng)結(jié)束,開始講解rest_framework框架

在snippets目錄下創(chuàng)建serializers.py 用于序列化對(duì)象
(序列化: 用于字典與對(duì)象的直接的互轉(zhuǎn),相信從事ios開發(fā),安卓開發(fā)等攻城獅應(yīng)該不陌生)

# serializers.py 
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES

class SnippetSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

    def create(self, validated_data):
        """
        Create and return a new `Snippet` instance, given the validated data.
        """
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `Snippet` instance, given the validated data.
        """
        instance.title = validated_data.get('title', instance.title)
        instance.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()
        return instance

rest_framework框架提供了一個(gè)更加方便的方式來定義序列化文件

# serializers.py 
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES

class SnippetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Snippet
        fields = ('id','title', 'code', 'linenos', 'language', 'style')

無需再定義序列化的字段及字段的類型,只需重寫Meta類,定義model是哪個(gè)類的,fields則是在http請(qǐng)求后返回什么字段。是不是對(duì)比與上面編寫的序列化方便簡單得多。

我們開始來定義views.py文件。官方文檔中定義了幾個(gè)實(shí)現(xiàn)方式。現(xiàn)在我們?yōu)榇蠹乙灰恢v解一下
?前兩個(gè)實(shí)現(xiàn)方式是通過request方式來實(shí)現(xiàn),三到五是通過創(chuàng)建View來實(shí)現(xiàn),六則通過viewSet來實(shí)現(xiàn)

# urls.py
# 針對(duì)request
url(r'^snippets/$',views.snippet_list, name='snippet-list')          

# 針對(duì)view
url(r'^snippets/$',views.SnippetList.as_view(), name='snippet-list')  

# 針對(duì)的是viewSet
snippet_list = SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
url(r'^snippets/$', snippet_list, name='snippet-list'),

實(shí)現(xiàn)方式 一

# views.py
from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from rest_framework import status
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

@csrf_exempt
def snippet_list(request):
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data, safe=False)

    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)
  1. 定義@csrf_exempt 是為了避免 csrf攻擊 ①

  2. GET請(qǐng)求是獲取Snippet類中所有的對(duì)象snippets
    — 通過SnippetSerializer類序列化出serializer對(duì)象
    — 返回序列化對(duì)象的data數(shù)據(jù)(返回JSON字符串)

  3. POST請(qǐng)求是通過JSONParser().parse(request)
    — 把request請(qǐng)求中數(shù)據(jù)通過JSONParser類轉(zhuǎn)化為序列化的data數(shù)據(jù)
    — 對(duì)data數(shù)據(jù)進(jìn)行序列化,判斷序列化是否有效,有效則保存到本地?cái)?shù)據(jù)庫中

①(通過 裝飾器 對(duì)該方法進(jìn)行修改,如果不知道裝飾器可百度查閱,這是一個(gè)python語法)

實(shí)現(xiàn)方式 二

# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

@api_view(['GET', 'POST'])
def snippet_list(request,format=None):
    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)
  1. @api_view(['GET', 'POST']) 告訴該方法只運(yùn)行GET ,POST 兩個(gè)方法,內(nèi)部也對(duì)csrf攻擊做了處理

  2. GET請(qǐng)求實(shí)現(xiàn)方式與上面的例子完全一樣,只是在POST請(qǐng)求中,減少JSONParser類的實(shí)現(xiàn)。直接通過request.data獲得。 只是因?yàn)樵谘b飾器@api_view()中做了處理

實(shí)現(xiàn)方式 三

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

class SnippetList(APIView):
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        dict = {'code':0000,'data':serializer.data,'msg':"success"}
        return Response(dict)

    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)

這個(gè)是我最喜歡的方式因?yàn)樗钦嬲槍?duì)一個(gè)視圖的方式。通過視圖中個(gè)get方法 post方法去實(shí)現(xiàn)邏輯處理,而且更加自定義化,為什么會(huì)說自定義化呢,參考下面的幾個(gè)方式,你就會(huì)理解該框架在實(shí)現(xiàn)簡單化的過程卻失去了自定義化的缺點(diǎn)

實(shí)現(xiàn)方式 四

# views.py
from rest_framework import mixins
from rest_framework import generics
from rest_framework import status
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer


class SnippetList(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

在這里我就不多詳細(xì)講解,因?yàn)榉绞轿鍖?duì)方式四做了優(yōu)化

實(shí)現(xiàn)方式 五

# views.py
from rest_framework import generics
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

如果直接跳到這一步,大家一定是一臉懵逼的。這格式是其實(shí)也沒什么好講解,優(yōu)點(diǎn)實(shí)現(xiàn)快,缺點(diǎn)不夠靈活。這就是我為什么說喜歡 實(shí)現(xiàn)方式三 的原因。

實(shí)現(xiàn)方式 六

from rest_framework import viewsets
class SnippetViewSet(viewsets.ReadOnlyModelViewSet):
    """
    This viewset automatically provides `list` and `detail` actions.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

rest_framework 從官方網(wǎng)提供的這六個(gè)方法中,從代碼的繁多到最后的兩行代碼實(shí)現(xiàn)一個(gè)請(qǐng)求的方式。從例子中的四五六,雖然實(shí)現(xiàn)起來特別簡單,不需要去判斷邏輯,不需要去手動(dòng)的實(shí)現(xiàn)序列化就能得到預(yù)期效果。但卻失去了復(fù)雜的邏輯判斷,及response 自由的格式。方法三對(duì)比其他可能較為麻煩,但是卻能滿足各公司不同需求的邏輯。如果有時(shí)間的話我會(huì)研究一下tornado,與django進(jìn)行一個(gè)對(duì)比

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

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