Django REST framework 序列化與反序列化(4)

RomanceSky發表於2018-05-31

關於什麼是序列化和反序列化(4) 【緊跟前一節】

【轉
https://blog.csdn.net/YangHeng816/article/details/78534186
POST 請求---------> 反序列化過程------->

deserializer: Json → native datatype【data = JSONParser().parse(BytesIO(content))】 →  isntance【serializer = SnippetSerializer(data=data)
 serializer.is_valid()# True serializer.save()】

GET 請求 ----------> 序列化過程---------->

serilization : isntance(django 模型例項) → native datatype(python 原生資料型別)【serializer.data】 → Json【JSONRenderer().render(serializer.data)】,將model例項的轉為json格式response出去。

從REST的設計原則看,它實際上是為了滿足客戶端的需求,現在的web後端與客戶端(ios/android)打交道的多,這樣的格式化response更便於它們解析。換句話說就是:將response打包成某種格式(如JSON)的東西。
】
複製程式碼

官方文件解釋

SerializerMethodField 這是一個只讀欄位。

它通過呼叫它所連線的序列化器類的方法來獲取它的值 它可以用於向物件的序列化表示新增任何型別的資料

Signature: SerializerMethodField(method_name=None)

method_name——要呼叫的序列化器上的方法的名稱。

如果不包括此預設值,則get_<field_name>。

method_name引數引用的序列化器方法應該接受一個引數(除了self),這個引數是被序列化的物件。

它應該返回您希望包含在物件的序列化表示中的任何內容

現在我們來試試

完整例項程式碼

models.py
from django.db import models

# Create your models here.
from django.contrib.auth.models import AbstractBaseUser


class MyUsers(models.Model):
    #REQUIRED_FIELDS = ('name',)
    #USERNAME_FIELD = ('name')
    groups = models.ForeignKey(
        'Groups',
        null=False,
        blank=False,
        related_name='myusers',
        on_delete=models.CASCADE
    )
    name = models.CharField(
            null=False,
            blank=False,
            max_length=125,
    )
    email = models.EmailField(
            null=False,
            blank=False,
            max_length=125,
    )

    url = models.URLField(
            null=False,
            blank=True,
            max_length=125,
    )


class Groups(models.Model):
    name = models.CharField(
            null=False,
            blank=False,
            max_length=125,
    )

    url = models.URLField(
            null=False,
            blank=True,
            max_length=125,
    )

class Ip(models.Model):
    user = models.ForeignKey(
        'MyUsers',
        null=False,
        blank=False,
        related_name='ips',
        on_delete=models.CASCADE
    )
    group = models.ForeignKey(
        'Groups',
        null=False,
        blank=True,
        related_name='ips',
        on_delete=models.CASCADE
    )
    ip_addr = models.GenericIPAddressField(
        blank=False,
        null=False,
    )

serializers.py
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from accounts.models import Ip


class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups', 'user')


class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')


class IpSerializer(serializers.HyperlinkedModelSerializer):
    #SerializerMethodField(): Serialization and deserialization
    group = serializers.SerializerMethodField()
    user = serializers.SerializerMethodField()
    class Meta:
        model = Ip
        fields = ('user',  'ip_addr', 'group')

    def get_group(self, obj):# 呼叫所連線的序列化器類的方法
        print(obj)
        group = obj.group
        print(group)
        print(group.url)
        return{'url': group.url,
               'name': group.name,
              }

    def get_user(self, obj):# 向物件的序列化表示新增任何型別的資料
        print(obj)
        user = obj.user
        print(user)
        if user:
            print(1)
        return {
            'name': user.name + ' ' + 'hello'
        }
        
views.py
from django.shortcuts import render
# Create your views here.
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from accounts.serializers import UserSerializer, GroupSerializer, IpSerializer
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from knox.auth import TokenAuthentication
from knox.models import AuthToken
from rest_framework.permissions import IsAuthenticated, AllowAny
from accounts.models import Ip


class UserViewSet(viewsets.ModelViewSet):
    authentication_classes = (
        TokenAuthentication,
    )
    permission_classes = (AllowAny,)
    queryset = User.objects.all().order_by('-date_joined').prefetch_related('groups')
    serializer_class = UserSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        auth_token = AuthToken.objects.create(user)
        # print(auth_token)
        return Response(
            {
                "email": user.email,
                "token": auth_token,
                "id": user.id,
                #"key": auth_token.key,
            }
        )


        """

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        self.token = AuthToken.objects.create(user)
        print(request.user)
        self.headers = self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token)
        # token is setted into the requested headers
        # token = Token.objects.create(user=user)
        print(self.token.key)
        """


# class UserViewSet(viewsets.ModelViewSet):
#     """
#     允許使用者檢視或編輯的API路徑。
#     """
#     queryset = User.objects.all().order_by('-date_joined')
#     serializer_class = UserSerializer
#     def Post(self, request, *args, **kwargs):
#                 serializer = self.get_serializer(data=request.data)
#                 serializer.is_valid(raise_exception=True)
#                 user = serializer.save()
#                 token = Token.objects.create(user=user)
#                 print(token.key)
#                 # auth_token = AuthToken.objects.create(user)
#                 # print(auth_token.key)
#                 return Response(
#                         {
#                             "name": user.username,
#                             "token": token,
#                             "id": user.id,
#                         }
#                 )
#

class GroupViewSet(viewsets.ModelViewSet):
    """
    允許組檢視或編輯的API路徑。
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer


class IpViewSet(viewsets.ModelViewSet):
    """
    允許組檢視或編輯的API路徑。
    """
    queryset = Ip.objects.all()
    serializer_class = IpSerializer
前面的都是專案下的應用Floral/
                        Floral/
                            accounts下的檔案
下面是專案Floral下的檔案

Floral/urls.py(注意:專案下的url)
from django.conf.urls import url, include
from rest_framework import routers
from accounts import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
router.register(r'ips', views.IpViewSet)

# 使用自動URL路由連線我們的API。
# 另外,我們還包括支援瀏覽器瀏覽API的登入URL。
urlpatterns = [
    url(r'api/auth/', include('knox.urls')),
    url(r'^', include(router.urls)),
    # url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]



複製程式碼

重點要解釋的部分 通過SerializerMethodField實現序列化 group是Ip表中的外來鍵,關聯MyUser模型 通過get_group()方法來設定返回的資料 user則是自定義的序列化欄位 通過get_user()方法來設定返回的資料



class IpSerializer(serializers.HyperlinkedModelSerializer):
    #SerializerMethodField(): Serialization and deserialization
    group = serializers.SerializerMethodField()
    user = serializers.SerializerMethodField()
    class Meta:
        model = Ip
        fields = ('user',  'ip_addr', 'group')

    def get_group(self, obj):# 呼叫所連線的序列化器類的方法
        print(obj)
        group = obj.group
        print(group)
        print(group.url)
        return{'url': group.url,
               'name': group.name,
              }

    def get_user(self, obj):# 向物件的序列化表示新增任何型別的資料
        print(obj)
        user = obj.user
        print(user)
        if user:
            print(1)
        return {
            'name': user.name + ' ' + 'hello'
        }
複製程式碼

執行python manage.py runserver後,訪問網址http://127.0.0.1:8000/ips/,出現的結果


Django version 2.0.5, using settings 'Floral.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
(0.002) SELECT "accounts_ip"."id", "accounts_ip"."user_id", "accounts_ip"."group_id", "accounts_ip"."ip_addr" FROM "accounts_ip"; args=()
Ip object (1)
(0.001) SELECT "accounts_myusers"."id", "accounts_myusers"."groups_id", "accounts_myusers"."name", "accounts_myusers"."email", "accounts_myusers"."url" FROM "accounts_myusers" WHERE "accounts_myusers"."id" = 1; args=(1,)
MyUsers object (1)
1
Ip object (1)
(0.001) SELECT "accounts_groups"."id", "accounts_groups"."name", "accounts_groups"."url" FROM "accounts_groups" WHERE "accounts_groups"."id" = 1; args=(1,)
Groups object (1)
http://www.baidu.com
[31/May/2018 07:51:52] "GET /ips/ HTTP/1.1" 200 105
複製程式碼

使用postman測試的結果 圖: https://note.youdao.com/yws/res/32197/WEBRESOURCE349824a3428c554357e2b7a7c27f7792

相關文章