上一章講解 《這絕對(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)
定義@csrf_exempt 是為了避免 csrf攻擊 ①
GET請(qǐng)求是獲取Snippet類中所有的對(duì)象snippets
— 通過SnippetSerializer類序列化出serializer對(duì)象
— 返回序列化對(duì)象的data數(shù)據(jù)(返回JSON字符串)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)
@api_view(['GET', 'POST']) 告訴該方法只運(yùn)行GET ,POST 兩個(gè)方法,內(nèi)部也對(duì)csrf攻擊做了處理
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ì)比