Django Rest 框架 -- 官方教程翻譯:1:序列化

我覺得官方文檔十分不錯(cuò)赂韵,比我搜到的教程要靠譜送淆,按照教程敲一遍,再仔細(xì)琢磨琢磨摊灭,感覺懂了不少咆贬。

教程1:序列化

1. 1 介紹:

本教程將介紹如何創(chuàng)建一個(gè)簡(jiǎn)單的粘貼代碼,突出顯示W(wǎng)eb API斟或。
一路上素征,將介紹組成REST框架的各種組件,并全面了解一切如何融合在一起萝挤。

該教程是相當(dāng)深入的御毅,所以你應(yīng)該在開始之前獲得一個(gè)cookie和一杯你最喜歡的釀造。
如果您只想快速瀏覽怜珍,請(qǐng)改用快速入門文檔端蛆。

注意:本教程的代碼可在GitHub的tomchristie / rest-framework-tutorial存儲(chǔ)庫(kù)中可以找到。

完成的實(shí)施也是在線作為沙盒版本進(jìn)行測(cè)試酥泛,這里可以看到今豆。

1.2 建立一個(gè)新的環(huán)境

在我們做任何事情之前,我們將使用virtualenv創(chuàng)建一個(gè)新的虛擬環(huán)境柔袁。這將確保我們的包配置與我們正在開展的任何其他項(xiàng)目保持良好的隔離呆躲。

PS:其實(shí)Python3.6可以用自帶的venv。

virtualenv env
source env/bin/activate

現(xiàn)在我們?cè)谝粋€(gè)virtualenv環(huán)境中捶索,我們可以安裝我們的包的要求插掂。

pip install django
pip install djangorestframework
pip install pygments

PS:pygments庫(kù)提供代碼高亮

注意:要隨時(shí)退出virtualenv環(huán)境,只需鍵入deactivate腥例。有關(guān)更多信息辅甥,請(qǐng)參閱 virtualenv文檔

1.3 入門:

好的燎竖,我們準(zhǔn)備好獲得代碼璃弄。要開始,我們先來創(chuàng)建一個(gè)新的項(xiàng)目构回。

cd ~
django-admin.py startproject tutorial
cd tutorial

一旦完成夏块,我們可以創(chuàng)建一個(gè)我們將用來創(chuàng)建一個(gè)簡(jiǎn)單的Web API的應(yīng)用程序。

python manage.py startapp snippets

我們需要添加我們的新snippets應(yīng)用和rest_framework應(yīng)用INSTALLED_APPS捐凭。我們來編輯tutorial/settings.py文件:

INSTALLED_APPS = (
    ...
    'rest_framework',
    'snippets.apps.SnippetsConfig',
)

請(qǐng)注意拨扶,如果你使用的Django <1.9,則需要更換snippets.apps.SnippetsConfig有snippets茁肠。

好的,我們準(zhǔn)備好了缩举。

1.4 創(chuàng)建一個(gè)可以使用的模型

為了本教程的目的匹颤,我們將首先創(chuàng)建一個(gè)Snippet用于存儲(chǔ)代碼片段的簡(jiǎn)單模型托猩。繼續(xù)編輯snippets/models.py文件。注意:良好的編程實(shí)踐包括評(píng)論京腥。雖然您將在本教程代碼的存儲(chǔ)庫(kù)版本中找到它們赦肃,但我們?cè)诖撕雎粤怂鼈儯瑢W⒂诖a本身他宛。

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

我們還需要為我們的代碼段模型創(chuàng)建初始遷移欠气,并首次同步數(shù)據(jù)庫(kù)厅各。

python manage.py makemigrations snippets
python manage.py migrate

1.5 創(chuàng)建一個(gè)Serializer類

我們需要開始使用Web API的第一件事是提供一種將代碼片段實(shí)例序列化和反序列化為表示形式的方法json。我們可以通過聲明與Django表單非常相似的序列化器來做到這一點(diǎn)预柒。在snippets命名的目錄中創(chuàng)建一個(gè)文件,serializers.py并添加以下內(nèi)容宜鸯。

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

序列化器類的第一部分定義了序列化/反序列化的字段淋袖。該create()和update()方法定義實(shí)例如何完全成熟的創(chuàng)建或修改時(shí)調(diào)用serializer.save()

甲串行類非常類似于一個(gè)Django Form類,并且包括關(guān)于各個(gè)字段類似的驗(yàn)證標(biāo)記适贸,如required,max_length和default拜姿。

字段標(biāo)志還可以控制在某些情況下蕊肥,如渲染到HTML時(shí)如何顯示串行器。{'base_template': 'textarea.html'}上面的標(biāo)志相當(dāng)于widget=widgets.Textarea在Django Form類上使用壁却。這對(duì)于控制如何顯示可瀏覽的API特別有用,我們將在本教程的后面看到赔硫。

我們實(shí)際上也可以通過使用ModelSerializer課程來節(jié)省自己的時(shí)間盐肃,我們稍后會(huì)看到权悟,但是現(xiàn)在我們將保持我們的序列化器定義推盛。

1.6 使用serializers

在我們進(jìn)一步了解之前,我們將熟悉使用我們新的Serializer類耘成。我們進(jìn)入Django shell。

python manage.py shell

好的瘪菌,一旦進(jìn)入我們有幾個(gè)庫(kù)要導(dǎo)入撒会,我們來創(chuàng)建一些代碼片段來處理。

注意:以下部分在shell里面編寫控嗜,需要一行一行寫,這樣才能看到結(jié)果:

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()

我們現(xiàn)在有幾個(gè)片段實(shí)例可以玩曾掂。我們來看看序列化這些實(shí)例之一壁顶。

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

此時(shí),我們將模型實(shí)例轉(zhuǎn)換為Python本機(jī)數(shù)據(jù)類型许蓖。為了完成序列化過程调衰,我們將數(shù)據(jù)轉(zhuǎn)換成json。

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

反序列化是類似的嚎莉。首先我們將一個(gè)流解析為Python本機(jī)數(shù)據(jù)類型...

from django.utils.six import BytesIO

stream = BytesIO(content)
data = JSONParser().parse(stream)

然后我們將這些本機(jī)數(shù)據(jù)類型恢復(fù)到完全填充的對(duì)象實(shí)例中趋箩。

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>

請(qǐng)注意API與表單的使用情況。當(dāng)我們開始編寫使用我們的串行器的視圖時(shí)跳芳,相似性將變得更加明顯竹勉。

我們也可以序列化查詢集而不是模型實(shí)例。為此,我們只many=True需要為serializer參數(shù)添加一個(gè)標(biāo)志车胡。

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')])]

注意:下方的代碼為代碼優(yōu)化說明照瘾,并不代表要寫丧慈!

1.7 使用ModelSerializers

我們的SnippetSerializer類正在復(fù)制Snippet模型中還包含的大量信息逃默。如果我們可以保持我們的代碼更簡(jiǎn)潔,那將是很好的完域。

與Django提供Form類和ModelForm類的方式相同,REST框架包括Serializer類和ModelSerializer類凹耙。

我們來看看使用ModelSerializer類重構(gòu)我們的serializer 肠仪。snippets/serializers.py再次打開該文件,并用SnippetSerializer以下替換該類意述。

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

序列化器具有的一個(gè)不錯(cuò)的屬性是可以通過打印其表示來檢查序列化器實(shí)例中的所有字段吮蛹。打開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類不會(huì)做任何特別神奇的事情然低,它們只是創(chuàng)建序列化器類的快捷方式:

  • 一組自動(dòng)確定的字段。
  • 簡(jiǎn)單的默認(rèn)實(shí)現(xiàn)create()和update()方法带兜。

1.8 使用我們的Serializer編寫正常的Django視圖

我們來看看我們?nèi)绾问褂梦覀兊男碌腟erializer類編寫一些API視圖吨灭。目前我們不會(huì)使用任何REST框架的其他功能,我們只需將視圖編寫為常規(guī)的Django視圖无畔。

編輯snippets/views.py文件,并添加以下內(nèi)容恭理。

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的根本將是一個(gè)視圖郭变,支持列出所有現(xiàn)有的片段,或創(chuàng)建一個(gè)新的片段诉濒。

@csrf_exempt
def snippet_list(request):
    """
    List all code snippets, or create a new snippet.
    """
    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)

請(qǐng)注意未荒,因?yàn)槲覀兿M軌驈牟痪哂蠧SRF令牌的客戶端對(duì)此視圖進(jìn)行POST,因此我們需要將視圖標(biāo)記為csrf_exempt寨腔。這不是你通常想要做的事情划纽,REST框架視圖實(shí)際上比這更有明確的行為,但它現(xiàn)在將用于我們的目的勇劣。

我們還需要一個(gè)與單個(gè)代碼段對(duì)應(yīng)的視圖,并可用于檢索幻捏,更新或刪除代碼段命咐。

@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)

最后我們需要把這些節(jié)點(diǎn)連接起來醋奠。創(chuàng)建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),
]

我們還需要在tutorial/urls.py文件中連接根urlconf ,以包含我們的片段應(yīng)用程序的URL沛善。

from django.conf.urls import url, include

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

值得注意的是塞祈,我們目前還沒有正確處理的幾個(gè)邊緣案例。如果我們發(fā)送格式錯(cuò)誤json,或者如果請(qǐng)求是使用視圖不處理的方法媳友,那么我們最終會(huì)出現(xiàn)500個(gè)“服務(wù)器錯(cuò)誤”響應(yīng)产捞。不過,現(xiàn)在這樣做搂抒。

1.9 測(cè)試我們?cè)赪eb API上的第一次嘗試

現(xiàn)在我們可以啟動(dòng)一個(gè)服務(wù)我們的代碼片段的示例服務(wù)器尿扯。

退出shell...

quit()

并啟動(dòng)Django的開發(fā)服務(wù)器焰雕。

python manage.py runserver

在另一個(gè)終端窗口中,我們可以測(cè)試服務(wù)器辟宗。

我們可以使用

curlhttpie來測(cè)試我們的API 吝秕。

Httpie是用Python編寫的用戶友好的http客戶端。
我們來安裝,您可以使用pip安裝httpie:

pip install httpie

最后容客,我們可以得到所有片段的列表:

http http://127.0.0.1:8000/snippets/

HTTP/1.1 200 OK
...
[
  {
    "id": 1,
    "title": "",
    "code": "foo = \"bar\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  },
  {
    "id": 2,
    "title": "",
    "code": "print \"hello, world\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  }
]

或者我們可以通過引用其id來獲取特定的代碼段:

http http://127.0.0.1:8000/snippets/2/

HTTP/1.1 200 OK
...
{
  "id": 2,
  "title": "",
  "code": "print \"hello, world\"\n",
  "linenos": false,
  "language": "python",
  "style": "friendly"
}

同樣约郁,您可以通過在Web瀏覽器中訪問這些URL來顯示相同??的json。

---end---

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末供置,一起剝皮案震驚了整個(gè)濱河市绽快,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌续担,老刑警劉巖艘绍,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異挎挖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)崔涂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門始衅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蝙茶,你說我怎么就攤上這事诸老。” “怎么了别伏?”我有些...
    開封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵厘肮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我耍属,道長(zhǎng)大咱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任溯捆,我火速辦了婚禮厦瓢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘煮仇。我一直安慰自己,他們只是感情好刨仑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辙诞,像睡著了一般轻抱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上较店,一...
    開封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天容燕,我揣著相機(jī)與錄音,去河邊找鬼捧杉。 笑死秘血,一個(gè)胖子當(dāng)著我的面吹牛评甜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忍坷,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼佩研,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了晰骑?” 一聲冷哼從身側(cè)響起绊序,我...
    開封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎骤公,沒想到半個(gè)月后阶捆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钦听,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倍奢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年娱挨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跷坝。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柴钻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贴届,到底是詐尸還是另有隱情,我是刑警寧澤占键,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布元潘,位于F島的核電站,受9級(jí)特大地震影響牲距,放射性物質(zhì)發(fā)生泄漏钥庇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一难述、第九天 我趴在偏房一處隱蔽的房頂上張望参咙。 院中可真熱鬧,春花似錦蕴侧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)剃氧。三九已至阻星,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間妥箕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工坎吻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宇葱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓诸尽,卻偏偏與公主長(zhǎng)得像印颤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

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