drf介绍

  • Django REST framework (简称:DRF)是一个强大而灵活的 Web API 工具。 遵循RESTFullAPI风格,功能完善,可快速开发API平台。

  • 官网文档:https://www.django-rest-framework.org

  • Django REST framework 最新版使用要求:

    • Python(3.6、3.7、3.8、3.9、3.10)
    • Django(2.2、3.0、3.1、3.2、4.0)

DRF安装与项目配置

DRF安装

pip install djangorestframework
pip install markdown
pip install django-filter

DRF项目配置与初探

  1. 创建django_drf项目

image-20221224221748667

  1. 创建app
E:\workspace\django-project\day1\django_drf>python manage.py startapp myapp
  1. Settings.py添加项目配置

image-20221224223222369

  1. 项目结构
django_drf
    │  manage.py
    │
    ├─django_drf
    │  │  asgi.py
    │  │  settings.py
    │  │  urls.py
    │  │  wsgi.py
    │  │  __init__.py
    │
    ├─myapp
    │  │  admin.py
    │  │  apps.py
    │  │  models.py
    │  │  tests.py
    │  │  views.py
    │
    └─templates
  1. 主路由配置: django_drf/urls.py
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myapp/', include('myapp/urls.py'))
]
  1. app路由: django_drf/myapp/urls.py
from django.urls import path,re_path
from myapp import views

urlpatterns = [

]

DRF初探之实现用户增删改查API

  1. 定义app数据模型: myapp/models.py
from django.db import models

class User(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    sex = models.CharField(max_length=16)
    age = models.IntegerField()
  1. 数据同步和迁移
E:\workspace\django-project\day1\django_drf>python manage.py makemigrations
E:\workspace\django-project\day1\django_drf>python manage.py migrate
  1. 编写app序列化器文件: myapp/serializers.py
from myapp.models import User
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'
  1. app试图函数: myapp/views.py
from myapp.models import User
from .serializers import UserSerializer
from rest_framework import viewsets

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
  1. app路由: myapp/urls.py
from django.urls import path,include
from myapp import views
from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'user', views.UserViewSet)

urlpatterns = [
    path('api/',include(router.urls))
]
  1. 启动项目访问: http://127.0.0.1:8000/myapp/api/

image-20221225200447485

  1. API信息提交: http://127.0.0.1:8000/myapp/api/user/

image-20221225200617151

  1. 接口信息概览
http://127.0.0.1:8000/myapp/api/user/   #列出所有数据
http://127.0.0.1:8000/myapp/api/user/1/   #对于指定数据进行更新,删除,查看操作

DRF序列化器

序列化与反序列化介绍

在日常开发中,会从别的API获取数据或者自己写API提供数据,数据格式一般都是采用JSON格式。这期间就会涉及两个专业术语:

  • **序列化:**将python对象转json,后端响应

  • **反序列化:**将json转为python对象, 后端处理数据需要转换成python对象

之前常用三种序列化方式:JSON

之前经常用json模式完成序列化与反序列化操作:

  • 序列化应用场景示例:用ORM查询数据,采用JSON格式API返回数据。
  • 反序列化应用场景示例:从别的API获取数据,在Python里处理。

之前常用三种序列化方式: Django内置Serializers模块

Serializers是Django内置的一个序列化器,可直接将Python对象转为JSON格式,但不支持反序列化

from django.core import serializers
obj = User.objects.all()
data = serializers.serialize('json', obj)

之前常用三种序列化方式: Django内置JsonResponse模块

JsonResponse模块自动将Python对象转为JSON对象并响应。

DRF序列化器

DRF中有一个serializers模块专门负责数据序列化,DRF提供的方案更先进、更高级别的序列化方案。

  • 序列化器支持三种类型:
    • **Serializer:**对Model(数据模型)进行序列化,需自定义字段映射。
    • **ModelSerializer:**对Model进行序列化,会自动生成字段和验证规则,默认还包含简单的create()和update()方法。
    • **HyperlinkedModelSerializer:**与ModelSerializer类似,只不过使用超链接来表示关系而不是主键ID。

Serializer用户查询接口

  1. 编写app序列化器文件: myapp/serializers.py
from rest_framework import serializers

class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()
    city = serializers.CharField()
    sex = serializers.CharField()
    age = serializers.CharField()
  1. app视图函数: myapp/views.py
from rest_framework.views import APIView
from rest_framework.response import Response

class UserApiView(APIView):
    def get(self,request,id=None):
        #获取单条数据
        if id:
            user_obj = User.objects.get(id=id)
            user_serializers = UserSerializer(user_obj)
        else:
        #返回所有数据
            queryset = User.objects.all()
            user_serializers = UserSerializer(queryset,many=True)
        return Response(user_serializers.data)
  1. app路由: myapp/urls.py
from django.urls import re_path
from myapp import views
urlpatterns = [
    re_path('api/user/$',views.UserApiView.as_view()),
    re_path('api/user/(?P<pk>\d+)/$',views.UserApiView.as_view()),
]
  1. 数据查看测试:

    a. http://127.0.0.1:8000/myapp/api/user/

    image-20221226004240775

​ b. 查看单条数据: http://127.0.0.1:8000/myapp/api/user/1/

image-20221226004319461

Serializer用户创建接口

上述的配置不变,只需要变动视图和序列化

  1. app视图函数: myapp/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from myapp.models import User
from .serializers import UserSerializer

class UserApiView(APIView):
    def get(self,request,id=None):
        #获取单条数据
        if id:
            user_obj = User.objects.get(id=id)
            user_serializers = UserSerializer(user_obj)
        else:
        #返回所有数据
            queryset = User.objects.all()
            user_serializers = UserSerializer(queryset,many=True)
        return Response(user_serializers.data)

    def post(self,request):
        #数据反序列化
        user_ser = UserSerializer(data=request.data)    #request.data是用户POST数据
        if user_ser.is_valid():
            #保存数据库
            user_ser.save()
            res = {'code': 200, 'msg': '创建用户成功'}
        else:
            res = {'code': 500, 'msg': '创建用户失败'}
        return Response(res)
  1. app序列化文件: myapp/serializers.py
from myapp.models import User
from rest_framework import serializers
class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()
    city = serializers.CharField()
    sex = serializers.CharField()
    age = serializers.IntegerField()

    def create(self, validated_data):
        return User.objects.create(**validated_data)
  1. 创建数据测试: http://127.0.0.1:8000/myapp/api/user/

image-20221226004451710

  1. 创建数据结果返回: http://127.0.0.1:8000/myapp/api/user/

image-20221226004537590

Serializer用户更新和删除接口

  1. app视图函数: myapp/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from myapp.models import User
from .serializers import UserSerializer
from rest_framework import viewsets

class UserApiView(APIView):
    def get(self,request,id=None):
        #获取单条数据
        if id:
            user_obj = User.objects.get(id=id)
            user_serializers = UserSerializer(user_obj)
        else:
        #返回所有数据
            queryset = User.objects.all()
            user_serializers = UserSerializer(queryset,many=True)
        return Response(user_serializers.data)

    def post(self,request):
        #数据反序列化
        user_ser = UserSerializer(data=request.data)    #request.data是用户POST数据
        if user_ser.is_valid():
            #保存数据库
            user_ser.save()
            res = {'code': 200, 'msg': '创建用户成功'}
        else:
            res = {'code': 500, 'msg': '创建用户失败'}
        return Response(res)

    def put(self,request,id=None):
        user_obj = User.objects.get(id=id)
        user_serializer = UserSerializer(instance=user_obj, data=request.data)
        if user_serializer.is_valid():
            user_serializer.save()
            res = {'code': 200, 'msg': '更新用户成功'}
        else:
            res = {'code': 500, 'msg': '更新用户失败'}
        return Response(res)
    
    def delete(self,request,id=None):
        user_obj = User.objects.get(id=id)
        user_obj.delete()
        res = {'code': 200, 'msg': '删除用户成功'}
        return Response(res)
  1. 序列化配置: myapp/serializers.py
from myapp.models import User
from rest_framework import serializers

class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()
    city = serializers.CharField()
    sex = serializers.CharField()
    age = serializers.IntegerField()

    def create(self, validated_data):
        return User.objects.create(**validated_data)

    def update(self, instance, validated_data):
        return User.objects.filter(id=instance.id).update(**validated_data)
  1. 数据更新测试: http://127.0.0.1:8000/myapp/api/user/1/

image-20221226005750655

  1. 状态查看:PUT之后查看

image-20221226005819334

  1. 删除数据: http://127.0.0.1:8000/myapp/api/user/3/

    image-20221226005903839

  2. 查看结果: http://127.0.0.1:8000/myapp/api/user/

image-20221226005945820

错误返回值优化

  • 在数据校验时候传入这个配置即可捕获异常,异常状态码是400: raise_exception=True

  • 需要修改app的视图函数: myapp/views.py

from myapp.models import User
from .serializers import UserSerializer
from rest_framework import viewsets

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer


from rest_framework.views import APIView
from rest_framework.response import Response

class UserApiView(APIView):
    def get(self,request,id=None):
        #获取单条数据
        if id:
            user_obj = User.objects.get(id=id)
            user_serializers = UserSerializer(user_obj)
        else:
        #返回所有数据
            queryset = User.objects.all()
            user_serializers = UserSerializer(queryset,many=True)
        return Response(user_serializers.data)

    def post(self,request):
        #数据反序列化
        user_serializer = UserSerializer(data=request.data)    #request.data是用户POST数据
        user_serializer.is_valid(raise_exception=True)
        user_serializer.save()
        res = {'code': 200, 'msg': '创建用户成功'}
        return Response(res)

    def put(self,request,id=None):
        user_obj = User.objects.get(id=id)
        user_serializer = UserSerializer(instance=user_obj, data=request.data)
        user_serializer.is_valid(raise_exception=True)
        user_serializer.save()
        res = {'code': 200, 'msg': '创建用户成功'}
        return Response(res)

    def delete(self,request,id=None):
        user_obj = User.objects.get(id=id)
        user_obj.delete()
        res = {'code': 200, 'msg': '删除用户成功'}
        return Response(res)
  • 更新和创建数据测试

DRF序列化器: 序列化器参数

  • 序列化器工作流程:

    • 序列化(读数据:视图里通过ORM从数据库获取数据查询集对象 -> 数据传入序列化器-> 序列化器将数据进行序列化 -> 调用序列化器的.data获取数据 -> 响应返回前端
    • 反序列化(写数据):视图获取前端提交的数据 -> 数据传入序列化器 -> 调用序列化器的.is_valid方法进行效验 -> 调用序列化器的.save()方法保存数据
  • 序列化器常用方法与属性:

    • serializer.is_valid():调用序列化器验证是否通过,传入raise_exception=True可以在验证失败时由DRF响应400异常。
    • serializer.errors:获取反序列化器验证的错误信息
    • serializer.data:获取序列化器返回的数据
    • serializer.save():将验证通过的数据保存到数据库(ORM操作)
  • 常用参数

image-20221226011345386

  • 通用参数

image-20221226011330068

  1. 调整myapp/serializers.py
from myapp.models import User
from rest_framework import serializers

class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(
        read_only=True
    )
    name = serializers.CharField(
        max_length=32,
        error_messages={
            "blank": "请输入名字",
            "required": "该字段必填",
            "max_length": "字段长度不能大于32"
        }
    )
    city = serializers.CharField()
    sex = serializers.CharField()
    age = serializers.IntegerField(
        min_value=1,
        max_value=100,
        error_messages={
            "blank": "请输入年龄",
            "required": "该字段必填",
            "min_value": "年龄最小值是1",
            "max_value": "年龄最大值是100"
        }
    )

    def create(self, validated_data):
        return User.objects.create(**validated_data)

    def update(self, instance, validated_data):
        return User.objects.filter(id=instance.id).update(**validated_data)
  1. 测试提交数据: http://127.0.0.1:8000/myapp/api/user/

image-20221227220652839

image-20221227220706911

DRF序列化器:扩展验证规则

如果常用参数无法满足验证要求时,可通过钩子方法扩展验证规则。

  • 局部钩子:validate_字段名(self, 字段值)
  • 全局钩子:validate(self, 所有校验的数据字典)
自定义验证器
  1. 修改myapp/serializers.py
from myapp.models import User
from rest_framework import serializers

def check_sex(data):
    if data.startswith('男') or data.startswith('女'):
        return data
    else:
        raise serializers.ValidationError("性别必须是男或女")

class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(
        read_only=True
    )
    name = serializers.CharField(
        max_length=32,
        error_messages={
            "blank": "请输入名字",
            "required": "该字段必填",
            "max_length": "字段长度不能大于32"
        }
    )
    city = serializers.CharField()
    sex = serializers.CharField(
        validators=[check_sex]
    )
    age = serializers.IntegerField(
        min_value=1,
        max_value=100,
        error_messages={
            "blank": "请输入年龄",
            "required": "该字段必填",
            "min_value": "年龄最小值是1",
            "max_value": "年龄最大值是100"
        }
    )

    def create(self, validated_data):
        return User.objects.create(**validated_data)

    def update(self, instance, validated_data):
        return User.objects.filter(id=instance.id).update(**validated_data)
  1. 接口数据提交测试: http://127.0.0.1:8000/myapp/api/user/

image-20221227221417335

  1. post提交返回值查看

image-20221227221437226

局部钩子

针对某个字段验证合法性

  1. 修改myapp/serializers.py
class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(
        read_only=True
    )
    name = serializers.CharField(
        max_length=32,
        error_messages={
            "blank": "请输入名字",
            "required": "该字段必填",
            "max_length": "字段长度不能大于32"
        }
    )
    city = serializers.CharField()
    sex = serializers.CharField(
        validators=[check_sex]
    )
    age = serializers.IntegerField(
        min_value=1,
        max_value=100,
        error_messages={
            "blank": "请输入年龄",
            "required": "该字段必填",
            "min_value": "年龄最小值是1",
            "max_value": "年龄最大值是100"
        }
    )

    def create(self, validated_data):
        return User.objects.create(**validated_data)

    def update(self, instance, validated_data):
        return User.objects.filter(id=instance.id).update(**validated_data)

    def validate_name(self,attrs):
        if attrs.startswith("阿"):
            return attrs
        else:
            raise serializers.ValidationError("名字必须以阿开头")
  1. 验证合法性: http://127.0.0.1:8000/myapp/api/user/

    image-20221227221957007

  2. 局部钩子返回值

image-20221227222025038

全局钩子

针对所有字段验证合法性

  1. 修改myapp/serializers.py
def check_sex(data):
    if data.startswith('男') or data.startswith('女'):
        return data
    else:
        raise serializers.ValidationError("性别必须是男或女")

class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(
        read_only=True
    )
    name = serializers.CharField(
        max_length=32,
        error_messages={
            "blank": "请输入名字",
            "required": "该字段必填",
            "max_length": "字段长度不能大于32"
        }
    )
    city = serializers.CharField()
    sex = serializers.CharField(
        validators=[check_sex]
    )
    age = serializers.IntegerField(
        min_value=1,
        max_value=100,
        error_messages={
            "blank": "请输入年龄",
            "required": "该字段必填",
            "min_value": "年龄最小值是1",
            "max_value": "年龄最大值是100"
        }
    )

    def create(self, validated_data):
        return User.objects.create(**validated_data)

    def update(self, instance, validated_data):
        return User.objects.filter(id=instance.id).update(**validated_data)

    def validate_name(self,attrs):
        if attrs.startswith("阿"):
            return attrs
        else:
            raise serializers.ValidationError("名字必须以阿开头")

    def validate(self, attrs):
        from re import findall
        if findall('\d+',attrs.get('city')):
            raise serializers.ValidationError("城市中不允许出现数字")
        else:
            return attrs
  1. 城市包含数字测试: http://127.0.0.1:8000/myapp/api/user/

image-20221227222602678

  1. 测试结果

image-20221227222632241

ModelSerializer

对Model进行序列化,会自动生成字段和验证规则,默认还包含简单的create()和update()方法。

  1. 修改myapp/serializers.py
from myapp.models import User
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'
        extra_kwargs = {
            'age': {'min_value': 16, 'max_value': 100, 'required': True},
            'name': {'max_length': 32, 'required': True},
        }
  1. 数据提交测试: http://127.0.0.1:8000/myapp/api/user/

image-20221227223718640

  1. 返回值

image-20221227223746352

HyperlinkedModelSerializer:

与ModelSerializer类似,只不过使用超链接来表示关系而不是主键ID。

  • 不常用,case失败

DRF序列化器: 关联表显示

  • 例如: 应用发布系统项目涉及表
    • 一对多: 一个项目有对个应用,一个应用只能属于一个项目
    • 多对多:一个应用部署到多台服务器,一个服务器部署多个应用

image-20221227230545547

  1. 定义myapp/models.py
from django.db import models

class User(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    sex = models.CharField(max_length=16)
    age = models.IntegerField()


class Project(models.Model):
    name = models.CharField(max_length=32)

class App(models.Model):
    name = models.CharField(max_length=32)
    project = models.ForeignKey(Project,on_delete=models.CASCADE)

class Server(models.Model):
    hostname = models.CharField(max_length=64)
    ip = models.GenericIPAddressField()
    app = models.ManyToManyField(App)
  1. 定义序列化器myapp/serializers.py
from myapp.models import Project,App,Server
from rest_framework import serializers

class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = '__all__'


class AppSerializer(serializers.ModelSerializer):
    class Meta:
        model = App
        fields = '__all__'


class ServerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = '__all__'
  1. 定义视图函数myapp/views.py
from myapp.models import Project,App,Server
from .serializers import ProjectSerializer,AppSerializer,ServerSerializer
from rest_framework.views import APIView
from rest_framework.response import Response

class ProjectView(APIView):
    def get(self, request, id=None):
        # 获取单条数据
        if id:
            project_obj = Project.objects.get(id=id)
            project_serializers = ProjectSerializer(project_obj)
        else:
            # 返回所有数据
            queryset = Project.objects.all()
            project_serializers = ProjectSerializer(queryset, many=True)
        return Response(project_serializers.data)

    def post(self, request):
        # 数据反序列化
        project_serializer = ProjectSerializer(data=request.data)  # request.data是用户POST数据
        project_serializer.is_valid(raise_exception=True)
        project_serializer.save()
        res = {'code': 200, 'msg': '创建project成功'}
        return Response(res)

class AppView(APIView):
    def get(self, request, id=None):
        # 获取单条数据
        if id:
            app_obj = App.objects.get(id=id)
            app_serializers = AppSerializer(app_obj)
        else:
            # 返回所有数据
            queryset = User.objects.all()
            app_serializers = UserSerializer(queryset, many=True)
        return Response(app_serializers.data)

    def post(self, request):
        # 数据反序列化
        app_serializer = AppSerializer(data=request.data)  # request.data是用户POST数据
        app_serializer.is_valid(raise_exception=True)
        app_serializer.save()
        res = {'code': 200, 'msg': '创建APP成功'}
        return Response(res)

class ServerView(APIView):
    def get(self, request, id=None):
        # 获取单条数据
        if id:
            server_obj = Server.objects.get(id=id)
            server_serializers = ServerSerializer(server_obj)
        else:
            # 返回所有数据
            queryset = Server.objects.all()
            server_serializers = ServerSerializer(queryset, many=True)
        return Response(server_serializers.data)

    def post(self, request):
        # 数据反序列化
        server_serializer = ServerSerializer(data=request.data)  # request.data是用户POST数据
        server_serializer.is_valid(raise_exception=True)
        server_serializer.save()
        res = {'code': 200, 'msg': '创建server成功'}
        return Response(res)
  1. 添加测试数据
E:\workspace\django-project\day1\django_drf>python manage.py makemigrations
E:\workspace\django-project\day1\django_drf>python manage.py migrate
E:\workspace\django-project\day1\django_drf>python manage.py shell
In [1]: from myapp.models import Project,App,Server
In [2]: Project.objects.create(name='电商项目')
In [3]: Project.objects.create(name='在线教育项目')
In [4]: Project.objects.create(name='大数据项目')
In [5]: dianshang = Project.objects.get(name="电商项目")
In [6]: zaixian = Project.objects.get(name="在线教育项目")
In [7]: dashuju = Project.objects.get(name="大数据项目")
In [8]: App.objects.create(name="portal", project=dianshang)
In [9]: App.objects.create(name="pay", project=dianshang)
In [10]: App.objects.create(name="order", project=dianshang)
In [11]: App.objects.create(name="k12",project=zaixian)
In [12]: App.objects.create(name="Devops",project=zaixian)
In [13]: App.objects.create(name="Python",project=zaixian)
In [14]: App.objects.create(name="Search",project=dashuju)
In [15]: App.objects.create(name="Analisise",project=dashuju)
In [16]: App.objects.create(name="Scien",project=dashuju)
In [17]: Analisise=App.objects.get(name='Analisise')
In [18]: Python=App.objects.get(name='Python')
In [19]: order=App.objects.get(name='order')
In [20]: Server.objects.create(hostname='python',ip='10.0.1.1')
In [21]: Server.objects.create(hostname='test2',ip='10.0.1.2')
In [22]: Server.objects.create(hostname='test3',ip='10.0.1.3')
In [23]: server1 = Server.objects.get(hostname='python')
In [24]: server2 = Server.objects.get(hostname='test2')
In [25]: server3 = Server.objects.get(hostname='test3')
In [26]: server1.app.add(Python)
In [27]: server2.app.add(Analisise)
In [28]: server2.app.add(order)
In [29]: server3.app.add(order)
In [30]: server3.app.add(Python)
  1. 创建路由: myapp/urls.py
from django.urls import re_path
from myapp import views

urlpatterns = [
    re_path('^api/project/$',views.ProjectView.as_view()),
    re_path('^api/app/$',views.AppView.as_view()),
    re_path('^api/server/$', views.ServerView.as_view()),
]
  1. 启动项目查看接口数据: http://127.0.0.1:8000/myapp/api/project/

image-20221228001001873

  1. 启动项目查看接口数据: http://127.0.0.1:8000/myapp/api/app/

image-20221228001054388

  1. 启动项目查看接口数据: http://127.0.0.1:8000/myapp/api/server/

image-20221228001111209

DRF序列化器: 关联表显示

上面例子中的8会存在关联表关系的数据,是通过列表和id的形式展示的

序列化器返回是当前模型中的字段,如果字段是外键时,返回的是外键对应id,如图所示,如果想要显示外键对应的详细信息如何做呢?

image-20221228001347972

  • 有两种方法:
    • 定义字段为外键对应序列化类:例如project=ProjectSerializer(read_only=True),这种适合针对某个外键字段。
    • 序列化类中Meta类启用depth:深度获取关联表数据,这种所有外键都会显示出来。
针对一对多外键形式的数据展示
  1. 调整myapp/serializers.py中的外键所在的类
class AppSerializer(serializers.ModelSerializer):
    project = ProjectSerializer()
    class Meta:
        model = App
        fields = '__all__'
  1. 重启项目测试: http://127.0.0.1:8000/myapp/api/app/

image-20221228001648369

此时可以显示外键关联的project的信息

针对多对多数据展示
  1. 调整myapp/serializers.py
class ServerSerializer(serializers.ModelSerializer):
    app = AppSerializer(many=True)
    class Meta:
        model = Server
        fields = '__all__'
  1. 重启项目测试: http://127.0.0.1:8000/myapp/api/server/

image-20221228002050496

针对depth的数据展示
  • 使用场景: 一对多,多对多
  1. 调整myapp/serializers.py
class AppSerializer(serializers.ModelSerializer):
    #project = ProjectSerializer()
    class Meta:
        model = App
        fields = '__all__'
        depth = 1


class ServerSerializer(serializers.ModelSerializer):
    # app = AppSerializer(many=True)
    class Meta:
        model = Server
        fields = '__all__'
        depth = 1
  1. app接口测试: http://127.0.0.1:8000/myapp/api/app/

image-20221228002404077

  1. server接口测试: http://127.0.0.1:8000/myapp/api/server/

image-20221228002427821

DRF序列化器:SerializerMethodField

DRF序列化器默认仅返回数据模型中已存在资源,如果想新增返回字段或者二次处理,该如何操作呢?用SerializerMethodFiled

示例:给项目API增加一个字段,这个字段数据可从别的表中获取

  1. 调整myapp/serializers.py中的project
class ProjectSerializer(serializers.ModelSerializer):
    app_count = serializers.SerializerMethodField()
    class Meta:
        model = Project
        fields = '__all__'

    def get_app_count(self,obj):
        return len(obj.app_set.all())
  1. 浏览器数据测试: http://127.0.0.1:8000/myapp/api/app/

image-20221228003821299

DRF序列化器:改变序列化和反序列化的行为

  • 可以通过重写下面两个方法改变序列化和反序列化的行为:

    • to_internal_value():处理反序列化的输入数据,自动转换Python对象,方便处理。
    • to_representation():处理序列化数据的输出
  • 示例:如果提交API的数据与序列化器要求的格式不符合,序列化器就会出现错误。这时就可以重写to_internal_value()方法只提取出我们需要的数据。

  1. 重写序列化器中的serializers: myapp/serializers.py
class ProjectSerializer(serializers.ModelSerializer):
    app_count = serializers.SerializerMethodField()
    class Meta:
        model = Project
        fields = '__all__'

    def get_app_count(self,obj):
        return len(obj.app_set.all())

    def to_internal_value(self, data):  #data是未验证的数据, 并处理成py字典
        print(data)
        return super().to_internal_value(data)

  1. 启动项目测试: http://127.0.0.1:8000/myapp/api/project/

image-20221231105811459

  1. 查看测试结果: http://127.0.0.1:8000/myapp/api/project/

image-20221231105830014

  • 处理序列化输出(响应后的数据二次处理)
  1. 修改serializers: myapp/serializers.py
class ProjectSerializer(serializers.ModelSerializer):
    #app_count = serializers.SerializerMethodField()
    class Meta:
        model = Project
        fields = '__all__'

    def get_app_count(self,obj):
        return len(obj.app_set.all())

    def to_representation(self, instance):
        #获取预返回前的数据
        data = super(ProjectSerializer, self).to_representation(instance)
        data['app_count'] = len(instance.app_set.all())
        return data

    def to_internal_value(self, data):  #data是未验证的数据, 并处理成py字典
        print(data)
        return super().to_internal_value(data)
  1. 浏览器测试:http://127.0.0.1:8000/myapp/api/project/

    image-20221231110321214