django rest framework我的學習筆記(三)————Tutorial1.Serialization

Serialization——序列化

官網地址html

前言

本教程將會介紹建立一個簡單webAPI。在整個學習的過程當中,將會逐一介紹到REST framework的各類組件,讓你全面的瞭解全部東西是若是組合在一塊兒的。
這個教程將會至關的詳細,因此在開始以前,你應該去來點餅乾,再喝上一些你喜歡的飲料。若是你只是想快速概覽,你應該查看Quickstart.
注意:本教程的代碼能夠在GitHub的 tomchristie/rest-framework-tutorial中找到。測試,這是一個測試連接。python

建立一個新的虛擬環境

使用 virtualenv建立一個虛擬環境.git

virtualenv env
source env/bin/activate

而後咱們在咱們建立的虛擬環境中安裝須要的包。github

pip install django
pip install djangorestframework
pip install pygments #使用它來代碼高亮

注意:使用 deactivate來隨時退出虛擬環境。更多的信息請查看Virtualenv documentationweb

準備

咱們這邊開始編寫代碼了。先來建立一個項目吧~shell

cd ~
django-admin.py startproject tutorial
cd tutorial

接下來,咱們建立一個app。django

python manage.py startapp snippets

咱們須要添加 snippetsrest_frameworkINSTALLED_APPS,在 tutorial/settings.py文件中:json

INSTALLED_APPS = {
    ...
    'rest_framework',
    'snippets.apps.SnippetsConfig',
}

注意:若是你使用的django<1.9,你須要替換 snippets.apps.SnippetsConfigsnippets
咱們能夠繼續上路了。segmentfault

建立model

在本教程中,咱們將建立一個簡單的model,這個model將用於儲存代碼片斷。
編輯 snippets/models.py文件。
注意:編寫註釋是一個好的習慣。服務器

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,defalut='')
    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')

執行命令,建立數據表:

python manage.py makemigrations snippets
    python manage.py migrate

建立Serializer

首先,咱們須要給咱們的web API 提供一種序列化和反序列化的呈現方式,如json
咱們能夠申明一個和django的forms差很少的serializers。建立一個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):
        return Snippet.objects.create(**validated_data)
       
    def update(self,instance,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

serializer的第一步是定義須要 序列化/反序列化 的字段。create()update()方法定義當serializer.save()時,若是建立和更新。
serializer類很是相似於Django的Form類。包括各個字段的驗證標記,例如 required,max_length,default
字段標記也可以控制serializer在某些環境中如何顯示,例如呈現爲HTML.
以前的{'base_template': 'textarea.html'}標記至關於django Form中的widget=widgets.Textarea`。

其實咱們使用ModelSerializer類更可以節省咱們的時間,但如今,咱們仍是顯示的定義咱們的字段。

開始工做

在咱們更進一步學習以前,咱們將經過django shell來熟悉serializer。

python manage.py shell

咱們須要導入咱們須要的東西,而後建立兩個snippet。

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

snippet = Snippet(code='foo="bar"\n')
snippet.save()

snippet = Snippet(code='print "hello, world"\n')
snippet.save()

咱們來看看咱們建立的其中一個實例:

serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}

在這裏,咱們翻譯這個model實例爲python原生的數據類型,爲了完成序列化,咱們將數據呈現爲JSON。

content = JSONRenderer().render(serializer.data)
content
# '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'

反序列化相似。首先,咱們解析一個流爲Python原生數據類型。

from django.utils.six import BytesIO
data = JSONParser().parse(stream)

而後咱們還原原生數據類型到一個徹底填充的對象實例中。

serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# OrderedDict([('title', ''), ('code', 'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
serializer.save()
# <Snippet: Snippet object>

注意:這相似於forms.當咱們編寫views使用serializer時,這會看起來更類似。

serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]

使用ModelSerializers

咱們的SnippetSerializer類複製了不少snippet中的東西。咱們但願咱們的代碼可以保持乾淨整潔。
相似於django有Form和ModelForm類,REST framework也包含SerializerModelSerializer兩個類。
讓咱們來使用ModelSerializer來重構咱們的serializer類。打開snippets/serializers.py,替換SinppetSerializer類:

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

serializer擁有一個很好的屬性,你可以經過打印查看一個serializer實例的全部字段。打開django shell(python manage.py shell):

from snippets.serializers import SnippetSerializer
serializer = SnippetSerializer()
print(repr(serializer))
# SnippetSerializer():
#    id = IntegerField(label='ID', read_only=True)
#    title = CharField(allow_blank=True, max_length=100, required=False)
#    code = CharField(style={'base_template': 'textarea.html'})
#    linenos = BooleanField(required=False)
#    language = ChoiceField(choices=[('Clipper', 'FoxPro'), ('Cucumber', 'Gherkin'), ('RobotFramework', 'RobotFramework'), ('abap', 'ABAP'), ('ada', 'Ada')...
#    style = ChoiceField(choices=[('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful')...

注意ModelSerializer不會作任何如魔法般的事情,它只是更快捷的建立serializer

  • 自動的肯定字段的設置
  • 簡單的默認create()update()方法

使用Serializer寫一個常規的django views

讓咱們使用咱們新的serializer來寫一些API視圖吧。在這裏,咱們不會使用任何REST framework的其餘特性,咱們就寫一個常規的 django views。
來編寫 snippets/views.py文件吧:

from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

咱們的API將會支持查看全部數據和建立一個新的snippet

@csrf_exempt
def snippet_list(request):
    """
    顯示全部的代碼片斷,或者建立一個新的片斷
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return JsonResponse(serializer.data, safe=False)

    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)

注意:由於咱們但願post可以不經過CSRF token的驗證,因此咱們使用了 csrf_exempt。事實上,這不會是你常常作的事情,而且REST framework views會更加明智的作這個事情。可是如今,他可使用。

咱們還須要這個視圖可以檢索,更新和刪除。

@csrf_exempt
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a code snippet.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return HttpResponse(status=404)

    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return JsonResponse(serializer.data)

    elif request.method == 'PUT':
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(snippet, data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data)
        return JsonResponse(serializer.errors, status=400)

    elif request.method == 'DELETE':
        snippet.delete()
        return HttpResponse(status=204)

最後,咱們須要建立url,在snippets/urls.py文件中

from django.conf.urls import url
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.snippet_list),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
]

咱們還須要在跟urls.py(tutorial/urls.py)上引入咱們的urls.py

from django.conf.urls import url, include

urlpatterns = [
    url(r'^', include('snippets.urls')),
]

注意:咱們的視圖有某些問題是尚未作妥善的處理,好比發送的json格式不正確,或是調用視圖沒有的方法,那麼咱們就會返回一個500「服務器錯誤」的消息。

相關文章
相關標籤/搜索