天天看點

django-rest-framework 序列化

下載下傳需要的包

pip install django
pip install djangorestframework
pip install pygments 
           

建立項目

django-admin startproject tutorial

cd tutorial

python manage.py startapp snippets
           

将snippets添加和rest_framework添加到INSTALLED_APPS中。 

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

建立使用的模型,編輯 snippets/models 子產品 .

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()])
# Create your models here.

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

    class Meta:
        ordering=['created']
           

建立模型之後需要同步資料庫。

python manage.py makemigrations snippets

python manage.py migrate

django-rest-framework 序列化

看到上面提示代表已經成功建立表。

 建立一個序列化的類

我們需要開始使用Web API的第一件事是提供一種将代碼段執行個體序列化和反序列化為諸如的表示形式的方法JSON.可通過聲明Django形式非常相似的序列化器來實作此目的。在

snippets

名為目錄的目錄中建立一個檔案,

serializers.py

然後添加以下内容。

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):
        """
             Create and return a new `Snippet` instance, given the 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
           

第一部分首先定義了要進行序列化/反序列化的字段。該create()和update()方法定義執行個體如何完全成熟的建立或修改時調用serializer.save()

類似Django的Form類,并且包括關于各個字段類似的驗證标記,如required,max_length和default。

字段标志還可以控制在某些情況下(例如HTML)應如何顯示序列化程式,{'base_template':'textarea.html'}上面的标志等效于

widget=widgets.Textarea 在Django的Form類上使用,這對于控制應如何顯示可浏覽的API尤其有用。可以通過ModelSerializer會更省時間。

使用序列化器

進入shell模式

python manage.py shell

>>> from snippets.models import Snippet
>>> from snippets.serializers import SnippetSerializer
>>> from rest_framework.renderes import JSONRenderer
>>> from rest_framework.renderers import JSONRenderer
>>> from rest_framework.parsers import JSONParser
>>> sinppet = Snippet(code='foo="bar"\n')
>>> sinppet.save()
>>> sinppet = Snippet(code='print("hello,world")\n')
>>> sinppet.save()
>>> serializer=SnippetSerializer(sinppet)
>>> serializer.data
# {'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}

>>> print(type(serializer.data))
<class 'rest_framework.utils.serializer_helpers.ReturnDict'>

           

上述已經把模型執行個體轉換未python本機的資料類型,為了完成序列化,需要将資料渲染到json中。

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

反序列化是相似的。首先,我們将流解析為Python本機資料。

>>> import io
>>> stream = io.BytesIO(content)
>>> 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>
           

這裡serializer.is_valid() 儲存的時候我第一次傳回的是False,用serializer.errors檢視。發現是style的值不是我定義的。修改與

之前與定義的SnippetSerializer中的style,default='friendly'值一緻即可。
           
>>> serializier.is_valid()
False
>>> serializier.errors
{'style': [ErrorDetail(string='"fridenly" is not a valid choice.', code='invalid_choice')]}
>>> data['style']='friendly'
>>> serializer=SnippetSerializer(data=data)
>>> serializer.is_valid()
True
           

請注意,API與處理表單的相似程度,當我們開始編寫使用序列化程式的視圖時,相似性應該變得更加明顯。我們還可以序列化查詢集而不是模型執行個體,為此,隻需要many=True 在序列化器參數中添加一個标記即可。

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

使用ModelSerializers

序列化器SnippetSerializer正在複制Snippet模型的許多資訊,如果代碼能更簡潔,那肯定是更好的。就像Django提供的Form和ModelForm類一樣,REST架構同時包含Serializer類和ModelSerializer類。

使用ModelSerializer該類重構序列化器。snippet/serializers.py再次編輯,并用序列化器SnippetSerializer以下内容替換該類。

class SnippetSerializer(serializers.ModelSerializer):

    class Meta:
        model = Snippet
        fields=['id','title','code','linenos','language','style']

           

你可以列印序列化程式的表示形式來檢查序列化程式執行個體中的所有字段。使用打開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類并沒有做任何特别的事情,它們隻是建立序列化器類的捷徑。

  • 自動确定的一組字段
  • create() 和 update()方法的簡單預設實作。

使用我們的序列化器編寫正常Django視圖

使用新的Serializer類編寫一些API視圖。目前我們不使用rest其他功能,隻是将視圖編寫為正常的Django視圖。

編寫snippets/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
           

API的根源将是一個視圖,該視圖支援列出所有現有的代碼片段或建立新的代碼片段。

@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)
        print(serializer.data)
        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):
    """
    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)
        print(serializer.data)
        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)
           

上述視圖可用于檢索,更新或删除該代碼段。

建立 snippets/urls.py

from django.urls import path
from snippets import views



urlpatterns = [
    path('snippets/',views.snippet_list),
    path('snippets/<int:pk>/',views.snippet_detail),
]
           

還需要連接配接tutorial/urls.py,包括我們片段用的URL。

from django.urls import path, include

urlpatterns = [
    path('', include('snippets.urls')),
]
           

現在可以來測試一下編寫好的API。

啟動djang的服務。python manage.py runserver

Performing system checks...

System check identified no issues (0 silenced).
June 11, 2020 - 19:32:22
Django version 2.1.4, using settings 'tutorial.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
           

使用浏覽器通路:

請求:http://127.0.0.1:8000/snippets/   響應

[
  {
    "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"
  }
]
           

請求:http://127.0.0.1:8000/snippets/1/  響應

django-rest-framework 序列化

到目前為止,有一個序列化API,與django的Form非常 相似。并且提供一些正常的視圖。

除了提供JSON響應外,我們的API視圖目前并沒有做任何特别的事情,而且我們仍然希望清理一些錯誤處理的極端情況,但這是一個正常運作的Web API。

學習連結 :官網文檔連結