本人普通一本,正值大三,爲了能有好的就業,痛定思痛戒掉遊戲!鞭策自己至少一週一篇博客
- 學習目標:學校課內基礎打紮實,課外學會語言框架,同時提升英語閱讀水平
- 學習路線(自擬):
vue
->djangorestframework
->goland
- 畢業前想:用前後端分離建成自己的小站,做一款網絡遊戲(愛好而已)
關於本篇djangorestframwork
內容皆會上傳到我的github上:https://github.com/BadbadLoli/django-rest-framework-study
本篇參照官網教程:https://www.django-rest-framework.org/tutorial/1-serialization/
學習爲主,如有紕漏請大神指正
介紹
本教程將介紹如何創建一個簡單的突出顯示代碼塊的Web API
。在此過程中,它將介紹構成REST框架的各種組件,並讓您全面瞭解所有內容是如何組合在一起的。
項目準備
創建一個新項目tutoria
l,並創建一個新的app snippets
django-admin startproject tutorial
...
python manage.py startapp snippets
然後我們需要告訴django
我們要使用snippets
和restframework
./tutorial/settings.py
INSTALLED_APPS = [
...
'rest_framework',
'snippets.apps.SnippetsConfig',
]
創建model
現在,我們創建一個簡單的Snippet
模型,用來存儲代碼塊的相關信息
./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, 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']
pygments
是一個優化markdown,對其中的代碼塊進行高亮的庫,不需要做深入瞭解
模型創建完之後要進行數據遷移
python manage.py makemigrations
...
python manage.py migrate
創建一個Serializer
現在,我們需要在Web API
上把snippet
實例序列化和反序列化爲json格式,我們可以通過聲明與django
中的表單非常相似的序列化器來實現這一點
./snippets/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):
# 創建返回一個新的Snippet實例,並附上驗證好的數據
return Snippet.objects.create(**validated_data)
def update(self, instance, validated_data):
# 更新返回一個存在的Snippet實例,並附上驗證好的數據
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()則定義了在調用save()方法時如何創建或修改實例
serializer與Django表單類非常相似,並且在各個字段上包含類似的驗證標誌,比如required、max_length和default
當然,我們也可以用ModelSerializer
類來節省時間,跟django中的表單類ModelForm
類一樣
./snippets/serializers.py
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ['id', 'title', 'code', 'linenos', 'language', 'style']
要記住,ModelSerializer
類只是創建serializer
的快捷方式,並沒有什麼神奇的功能,像create()
和update()
方法只是默認實現
使用python manage.py shell
打開django shell
然後嘗試以下操作:
- 我們要創建一些實例來使用
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': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}
- 我們還可以序列化
queryset
而不是模型實例。爲此,我們只需向序列化器參數添加一個many=True
標誌。
serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', ''), ('code', 'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', ''), ('code', 'print("hello, world")\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', ''), ('code', 'print("hello, world")'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]
編寫視圖View
讓我們看看如何使用serializer來編寫一些API視圖,目前,我們編寫的視圖爲普通的django視圖
./snippet/views.py
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
@csrf_exempt
def snippet_list(request):
# 展示(GET)所有snippet,或者創建(POST)一個新的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)
@csrf_exempt
def snippet_detail(request, pk):
# 檢索,更新或刪除一個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)
注意,由於我們希望能夠從沒有CSRF
令牌的客戶端向上面的視圖發送POST
請求,所以我們要給視圖函數加上@csrf_exempt
的裝飾器,其實drf視圖實際上有比這更合理的行爲,但現在爲了我們的教學目的,就先這樣做吧
最後,我們需要將這些視圖連接起來
./snippet/urls.py
from django.urls import path
from snippets import views
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>/', views.snippet_detail),
]
我們還要連接根url
./tutorial/urls.py
from django.urls import path, include
urlpatterns = [
path('', include('snippets.urls')),
]
值得注意的是,有幾個邊緣情況我們目前沒有正確處理。如果我們發送格式不正確的json,或者發送的請求視圖無法處理,那麼我們將得到一個500的“服務器錯誤”響應。不過,現在這樣就可以了。
測試一下我們的web API
python manage.py runserver
我用的postman進行測試
到目前爲止,我們做得還不錯,我們有一個序列化API,感覺非常類似於Django的表單API,以及一些常規的Django視圖。
目前,我們的API視圖除了提供json響應之外,沒有做任何特別的事情,我們仍然希望清理一些錯誤處理的邊緣情況,但它是一個功能良好的Web API。
我們將在本教程的第2部分中看到如何開始改進。