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

2,250 阅读3分钟

关于什么是序列化和反序列化(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