Django DRF API

Django 基本使用

前后端分离开发模式

1.1 前后端分离前

1.2 前后端分离前存在的一些问题

• PC、APP、Pad等多端流行 • 前后端开发职责不清晰:各司其职,最大程度减少开发难度,方便协作 • 开发效率问题,一般后端开发需先等前端页面准备好,有时前端也一直配 合后端,能力受限 • 前后端代码混在一起,日积月累,维护成本增加 • 后端开发语言和模板耦合

1.3 前后端分离开发模式

RestFulAPI

1.1 什么是RestfulAPI: • REST(Representational State Transfer,表征状态转移)是一种Web服务的软件架构风格。 描述网络中客户端与服务端的一种交互方式,它本身不常用,常用的是如何设计RestfulAPI (REST风格的网络接口) • RestfulAPI风格就是把所有的数据都当做资源,对表的操作就是对资源操作 • 资源就是指的URL,基于URL对资源操作,Web服务在URL上支持一系列请求方法,如下表所 示。

Django开发模式

1.1 Django工作流程

1.2 django案列创建一个用户信心管理实现增删改查

1.3.1 首先使用Pycharm创建一个新项目

1.3.2 创建应用myapp

python manage.py startapp myapp

1.3.3 myapp/models.py编写数据模型

from django.db import models

# Create your models here.
class User(models.Model):
    name = models.CharField(max_length=30)
    city = models.CharField(max_length=30)
    sex = models.CharField(max_length=30)
    age = models.IntegerField()

1.3.4 user_info项目重的settings.py中注册myapp

1.3.5 user_info 路由urls.py中定义myapp的路由

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myapp/', include('myapp.urls'))
]

1.3.6 同步数据库

python manage.py makemigrations python manage.py migrate

1.3.7 定义应用myapp路由urls.py

from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    # path('user/', views.user),
    path('user/', views.UserView.as_view()),
    path('user_add', views.user_add),
    path('user_edit', views.user_edit)
]

1.3.8 定义myapp试图views.py

from django.shortcuts import render
from django.http import HttpResponse, QueryDict, JsonResponse
from .models import User
from django.views.generic import  View

def user_add(request):
    return render(request, 'user_add.html')

def user_edit(request):
    id = request.GET.get('id')
    user_obj = User.objects.get(id=id)
    return render(request, 'user_edit.html', {'id': id, 'user': user_obj})

# def user(request):
#     if request.method == "GET":
#         if request.GET.get('id'):
#             pass
#             # user_obj = User.objects.get(id=request.GET.get('id'))
#             # res = {'code': 200, 'msg': '成功!', user_obj: user_obj}
#             # return JsonResponse(res)
#         else:
#             user_list = User.objects.all()
#             return render(request, 'user_list.html', {'user_list': user_list})
#     elif request.method == "POST":
#         name = request.POST.get('name')
#         city = request.POST.get('city')
#         sex = request.POST.get('sex')
#         age = request.POST.get('age')
#         User.objects.create(
#             name=name,
#             city=city,
#             sex=sex,
#             age=age
#         )
#         return HttpResponse("创建用户成功!")
#     elif request.method == "PUT":
#         data = QueryDict(request.body)
#         id = data.get('id')
#         user_obj = User.objects.get(id=id)
#         user_obj.city = data.get('city')
#         user_obj.sex = data.get('sex')
#         user_obj.age = data.get('age')
#         user_obj.save()
#         # 方式2
#         # data = {'city': data.get('city'), 'sex': data.get('sex'), 'age': data.get('age')}
#         # User.objects.filter(id=id).update(**data)
#         res = {'code': 200, 'msg': '更新成功!'}
#         return JsonResponse(res)
#     elif request.method == "DELETE":
#         data = QueryDict(request.body)
#         id = data.get('id')
#         try:
#             User.objects.get(id=id).delete()
#             res = {'code': 200, 'msg': '删除用户成功!'}
#         except Exception:
#             res = {'code': 500, 'msg': '删除用户失败!'}
#
#         return JsonResponse(res)

class UserView(View):
    def get(self, request):
        if request.GET.get('id'):
            pass
            # user_obj = User.objects.get(id=request.GET.get('id'))
            # res = {'code': 200, 'msg': '成功!', user_obj: user_obj}
            # return JsonResponse(res)
        else:
            user_list = User.objects.all()
            return render(request, 'user_list.html', {'user_list': user_list})

    def post(self, request):
        name = request.POST.get('name')
        city = request.POST.get('city')
        sex = request.POST.get('sex')
        age = request.POST.get('age')
        User.objects.create(
            name=name,
            city=city,
            sex=sex,
            age=age
        )
        return HttpResponse("创建用户成功!")

    def put(self, request):
        data = QueryDict(request.body)
        id = data.get('id')
        user_obj = User.objects.get(id=id)
        user_obj.city = data.get('city')
        user_obj.sex = data.get('sex')
        user_obj.age = data.get('age')
        user_obj.save()
        # 方式2
        # data = {'city': data.get('city'), 'sex': data.get('sex'), 'age': data.get('age')}
        # User.objects.filter(id=id).update(**data)
        res = {'code': 200, 'msg': '更新成功!'}
        return JsonResponse(res)

    def delete(self, request):
        data = QueryDict(request.body)
        id = data.get('id')
        try:
            User.objects.get(id=id).delete()
            res = {'code': 200, 'msg': '删除用户成功!'}
        except Exception:
            res = {'code': 500, 'msg': '删除用户失败!'}

        return JsonResponse(res)

1.3.9 创建添加、编辑、获取用户信息前端html

添加

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>创建用户</title>
</head>
<body>
<form action="">
    姓名: <input type="text" name="name"><br>
    城市: <input type="text" name="city"><br>
    姓名: <input type="text" name="sex"><br>
    年龄: <input type="text" name="age"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>

获取

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>列出所有用户</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
</head>
<body>
<button><a href="/myapp/user_add" target="_blank">创建用户</a></button>
<table border="1">
    <thead>
        <tr>
            <th style="display: none">ID</th>
            <th>姓名</th>
            <th>城市</th>
            <th>性别</th>
            <th>年龄</th>
            <th>操作</th>
        </tr>
    </thead>
    <tbody>
        {% for i in user_list %}
        <tr>
            <td style="display: none">{{ i.id }}</td>
            <td>{{ i.name }}</td>
            <td>{{ i.city }}</td>
            <td>{{ i.sex }}</td>
            <td>{{ i.age }}</td>
            <td>
                <button><a href="/myapp/user_edit?id={{ i.id }}" target="_blank">编辑</a></button>
                <button id="del" onclick="delUser(this)">删除</button>
            </td>
        </tr>
        {% endfor %}
    </tbody>
</table>
<script>
    function delUser(obj) {
        confirm = confirm('是否删除该用户?');
        if (confirm) {
            id = $(obj).parent().parent().find("td:eq(0)").text(); // 获取button父元素td,再获取td父元素tr,最后获取tr第一个td值
            data = {'id': id};
            $.ajax({
                type: 'DELETE',
                url: '/myapp/user/',
                data: data,
                success: function (result) {
                    if(result.code === 200) {
                        alert(result.msg);
                        location.reload();
                    } else {
                        alert(result.msg)
                    }
                }
            })
        }
    }
</script>

</body>
</html>

1.3.10 编辑

<head>
    <meta charset="UTF-8">
    <title>编辑用户</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
</head>
<body>
<h2>编辑用户</h2>
<form action="#">
    <input type="text" name="id" value="{{ user.id }}" style="display: none">
    姓名:<input type="text" name="name" value="{{ user.name }}"><br>
    城市:<input type="text" name="city" value="{{ user.city }}"><br>
    性别:<input type="text" name="sex" value="{{ user.sex }}"><br>
    年龄:<input type="text" name="age" value="{{ user.age }}"><br>
    <input type="button" value="提交" onclick="go()">
</form>
<script>
    function go() {
        id = $('input[name=id]').val();
        name = $('input[name=name]').val();
        city = $('input[name=city]').val();
        sex = $('input[name=sex]').val();
        age = $('input[name=age]').val();
        data = {'id': id, 'name': name, 'city': city, 'sex': sex, 'age': age};
        $.ajax({
            type: 'PUT',
            url: '/myapp/user/',
            data: data,
            success: function (result) {
                if ( result.code === 200 ) {
                    alert(result.msg)
                }
            }
        })
    }

</script>
</body>
</html>

1.3.11 启动myapp应用

Django REST Framework初探
DRF 实现用户增删改查

1 安装Django REST Framework

pip install djangorestframework

2 添加rest_framework到INSRTALLED_APPS设置中

3创建app

python manage.py startapp myapp_api

4 定义数据模型并同步数据库

from django.db import models

# Create your models here.
class User(models.Model):
    name = models.CharField(max_length=30)
    city = models.CharField(max_length=30)
    sex = models.CharField(max_length=30)
    age = models.IntegerField()

python manage.py makemigrations python manage.py migrate

5 编写序列化器文件myapp_api/serializers.py

from myapp.models import User
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User #指定数据类型
        fields = "__all__" #显示所有字段

6 定义视图

from rest_framework import viewsets
from .serializers import UserSerializer
from myapp.models import User
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all() #指定操作的数据
    serializer_class = UserSerializer #指定序列化器

7 添加API路由devops/urls.py和应用myapp/urls.py

from django.contrib import admin
from django.urls import path ,include,re.path


urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('myapp/',include('myapp.urls')),
    re_path('api/',include('myapp_api.urls')),
]
from django.urls import path,re_path,include
from myapp_api import  views
from rest_framework import routers

#自动注册路由
router = routers.DefaultRouter()
router.register(r'user',views.UserViewSet)

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

8 调用地址完成增删改查

Django DRF序列化器

什么是序列化?

序列化 (Serialization),是指把程序中的一个类转化成一个标准化的格式。标准化的意义是这个格式可以跨程序,跨平台的被使用,而且保持其原有的内容,规范。

为什么要对数据进行序列化?
  • 一致性:我们将要保存的数据,序列化成标准的格式(Json格式或者Pickle格式)。之后再反序列化回来,数据依然是原来的。保持了数据的一致性。

  • 有效性: 序列化之后,可以减少内存和网络资源的占用

  • 兼容性: 使用python进行了数据的序列化,也可以使用java或者其他语言进行反序列得到数据进行使用。

什么是序列化?什么是反序列化?
  • 序列化:将python对象转json

  • 反序列化: 将python对象转json

序列化器的工作流程:

序列化(读数据):视图通过ORM从数据库获取数据库查询集对象->数据传入序列化器->

序列化器对数据进行序列化->调用序列化器的.data获取数据->响应返回给前端

反序列化(写数据):试图获取前端提交数据-> 数据传入序列化器->调用序列化器的.is_valid方法效验数据->调用序列化器的.save()方法保存数据

序列化器常用方法与属性:
  • serializer.is_vaild():调用序列化器验证数据,传入raise_exception=True可以在验证失败时由DRF响应400异常

  • serializer.errors: 获取反序列化器验证的错误信息

  • serializer.data:获取序列化器返回的数据

  • serializer.save(): 将验证通过的数据保存到数据库(ORM操作)

DRF中序列化器支持的三种类型:
  • Serializer:对Model(数据模型)进行序列化,但是需要自定义字段映射

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

  • HyperlinkedModelSerializer: 与ModelSerializer类似,只不过使用超链接来表示关系而不是主键id

DRF序列化器使用
Serializer序列化器

1、获取所有用户(查)

1.1 定义序列化器 myapp_api/serializers.py

class UserSerializer(serializers.Serializer):
    #序列化器中定义的字段必须与使用模型字段对应
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=30)
    city = serializers.CharField(max_length=30)
    sex = serializers.CharField(max_length=30)
    age = serializers.IntegerField()

1.2 视图中使用定义好的序列化器 myapp_api/views.py

from rest_framework.views import APIView
from .serializers import UserSerializer
from myapp.models import User
from rest_framework.response import Response

# class UserViewSet(viewsets.ModelViewSet):
#     queryset = User.objects.all() #指定操作的数据
#     serializer_class = UserSerializer #指定序列化器
class UserView(APIView):
    def get(self,request):
        # 获取所有用户
        queryset = User.objects.all()
        # 调用序列化器将queryset对象转为json
        user_ser = UserSerializer(queryset,many=True) #如果序列化多条数据,需要指定many=True
        return Response(user_ser.data) #从.data属性中获取序列化结果

1.3定义路由myapp_api/urls.py

from django.urls import path,re_path,include
from myapp_api import  views

urlpatterns = [
    path('^api/user/$',views.UserView.as_view()),
]

2、获取单个用户

2.1 定义获取单个用户视图

from rest_framework.views import APIView
from .serializers import UserSerializer
from myapp.models import User
from rest_framework.response import Response

class UserView(APIView):
    def get(self,request,pk=None):
        if pk:
            # 获取单个用户
            user_obj = User.objects.get(id=pk)
            user_ser = UserSerializer(user_obj)#调用序列化器将获取的单个用户数据对象转换为json
        else:
        # 获取所有用户
            queryset = User.objects.all()
            # 调用序列化器将queryset对象转为json
            user_ser = UserSerializer(queryset,many=True) #如果序列化多条数据,需要指定many=True
        result = {'code':200,'msg': "获取用户成功",'data': user_ser.data}
        return Response(result) #从.data属性中获取序列化结果

2.2 定义路由myapp_api/urls.py

from django.urls import path,re_path,include
from myapp_api import  views
urlpatterns = [
    re_path('^api/user/$',views.UserView.as_view()),
    re_path('^api/user/(?P<id>\d)/$',views.UserView.as_view()),
]

2.3 获取单个用户测试

3 创建用户

3.1 定义视图myapp_api/views.py 增加post方法接收数据

    def post(self,request):
        #调用序列化器将提交的数据进行反序列化
        user_ser = UserSerializer(data=request.data)
        # 判断提交的数据反序列化是否通过验证
        if user_ser.is_valid():
            # 判断通过则保存到数据库
            user_ser.save()
            msg = '创建用户成功'
            code = 200
        else:
            msg = '提交数据格式不对!创建用户失败'
            code = 400
        result = {'code': code,'msg': msg}
        return Response(result)

3.2 myapp_api/serializers.py定义create()方法

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

    def create(self, validated_data): # 定义create方法validated_data是提交的json数据
        return User.objects.create(**validated_data)

3.3 测试创建用户

4、定义更新用户

4.1 定义视图: 增加myapp_api/views.py PUT方法接收数据

    def put(self,request,id=None):
        # 获取需要更新数据的用户,将用户默认pk赋值给id
        user_obj = User.objects.get(id=id)
        # 调用序列化器,传入已有的对象和提交数据
        user_ser = UserSerializer(instance=user_obj,data=request.data)
        if user_ser.is_valid():
            user_ser.save()
            msg = '更新用户成功'
            code = 200
        else:
            msg = '更新用户失败,数据格式不正确!'
            code = 400
        result = {'code': code, 'msg': msg}
        return Response(result)

4.2 myapp_api/serializers.py中增加update()方法

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

4.3 测试更新用户

5 、删除用户

5.1 定义删除单个用户视图myapp_api/views.py

    def delete(self,request,id=None):
        user_obj = User.objects.get(id=id)
        try:
            user_obj.delete()
            result = {'code': 200, 'msg': '用户删除成功'}
        except Exception as e:
            result = {'code': 500, 'mgs': '用户删除失败'}
        return Response(result)
ModelSerializer 序列化器

ModelSerializer 类型不需要自定义字段映射和定义create、update方法,使用起来方便很多! 如下使用ModelSerializer只需要定义视图、序列化器和自动注册路由

1 定义序列化器 myapp_api/serializers.py

 class UserSerializer(serializers.ModelSerializer): #定义序列化器类,并继承serializers.ModelSerializer
     class Meta:
         model = User #指定数据类型
         fields = '__all__' #显示所有字段

2 定义视图myapp_api/views.py

 class UserViewSet(viewsets.ModelViewSet):
     queryset = User.objects.all() #指定操作的数据
     serializer_class = UserSerializer #指定序列化器

3 定义自动注册路由

from django.urls import path,re_path,include
from myapp_api import  views
from rest_framework import routers

#自动注册路由
router = routers.DefaultRouter()
router.register(r'user',views.UserViewSet)

urlpatterns = [
    path('api',include(router.urls))
]
HyperModelSerializer 序列化器

与MedelSerializer使用方法一样。只不过它使用超链接来表示关系而不是主键ID。


# 更改序列化器
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = "__all__“
# 更改视图
user_ser = UserSerializer(queryset, many=True, context={'request': request})
# 更改路由
re_path('^api/user/$', views.UserView.as_view(), name="user-detail"),
re_path('^api/user/(?P<pk>\d+)/$', views.UserView.as_view(), name="user-detail"),

序列化器常用参数

1、 在myapp_api/serializers.py中设置序列花器参数

class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True) #当设置为True时该字段提交默认忽略
    name = serializers.CharField(max_length=30,
                                 error_messages={ # 设置错误提示
                                     "blank": "请输入姓名",
                                     "required": "该字段必填",
                                     "max_lenth": "字符长度不超过30",
                                 })
    city = serializers.CharField(max_length=10,
                                 error_messages={  # 设置错误提示
                                     "blank": "请输入城市",
                                     "required": "该字段必填",
                                     "max_lenth": "字符长度不超过10",
                                     })
    sex = serializers.CharField(max_length=10,
                                error_messages={  # 设置错误提示
                                    "blank": "请输入性别",
                                    "required": "该字段必填",
                                    "max_lenth": "字符长度不超10",
                                })
    age = serializers.IntegerField(min_value=18,max_value=100,
                                   error_messages={  # 设置错误提示
                                       "blank": "请输入年龄",
                                       "required": "该字段必填",
                                       "min_value": "年龄不低于18",
                                       "max_value": "年龄不超过100岁",
                                   })

2 、views.py视图修改方法中数据.is_valid(raise_exception=True),下面我只修改了post方法,其他方法修改也是一样的

    def post(self,request):
        #调用序列化器将提交的数据进行反序列化
        user_ser = UserSerializer(data=request.data)
        user_ser.is_valid(raise_exception=True)
        result = {'code': 200,'msg': '创建用户成功'}
        return Response(result)

3、测试post提交数据缺少age字段

序列器扩展验证规则

当常用参数无法满足验证要求时可以通过钩子方法扩展验证规则

  1. 局部钩子:validate_字段名(self, 字段值)

serializers.py中定义局部钩子

# 局部钩子: 针对某个字段验证合法性
    def validate_name(self,attrs): #attrs是该字段的值
        from re import  findall
        if findall('\d+',attrs):
            raise  serializers.ValidationError("姓名中不能包含数字!")
        else:
            return attrs

  1. 全局钩子:validate_字段名(self, 字段值)

# 全局钩子:针对所有字段验证
    def validate(self,attrs): #attrs是所有字段组成的字典
        sex = attrs.get('sex')
        if sex != "男" and sex != "女":
            raise serializers.ValidationError("性别只能是男/女!")
        else:
            return attrs

3 如果钩子也无法满足需求可以,自定义验证器。在序列化类外面定义验证器,使用validators参数指定验证器。

def check_name(data):
    if data.startswith("x"):
        raise serializers.ValidationError("姓名不能以x开头")
    else:
        return data
class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True) #当设置为True时该字段提交默认忽略
    name = serializers.CharField(max_length=30,validators=[check_name],
                                 error_messages={ # 设置错误提示
                                     "blank": "请输入姓名",
                                     "required": "该字段必填",
                                     "max_lenth": "字符长度不超过30",
                                 })
序列化器关联表显示

如应用发布系统项目涉及表

  • 一对多:一个项目有多个应用,一个应用只能属于一个项目

  • 多对多:一台应用可以部署到多台服务器,一个服务器也能部署多个应用

  1. 创建新应用Association_table

python manager.py startapp Association_table

  1. 定义数据模型,模型定义好了需要同步数据库

python manager.py makemigrations

python manager.py migrate

from django.db import models


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

class App(models.Model):
    name = models.CharField(max_length=30)
    project = models.ForeignKey(Project,on_delete=models.CASCADE) #一对多

class Server(models.Model):
    hostname = models.CharField(max_length=30)
    ip = models.GenericIPAddressField()
    app = models.ManyToManyField(App) #多对多
  1. 定义序列化器

from rest_framework import serializers
from Association_table.models import Project,App,Server

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 = Server
        fields = "__all__"
  1. 定义视图

from  rest_framework.views import APIView
from Association_table.models import Project,App,Server
from .serializers import ProjectSerializer,AppSerializer,ServerSerializer
from rest_framework.response import Response

# Create your views here.
class ProjectView(APIView):
    def get(self, request, id=None):
        if id:
            obj = Project.objects.get(id=id)
            ser = ProjectSerializer(obj)
        else:
            queryset = Project.objects.all()
            ser = ProjectSerializer(queryset, many=True)
        res = {'code': 200, 'msg': '获取成功!', 'data': ser.data}
        return Response(res)
    def post(self, request):
        ser = ProjectSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        res = {'code': 200, 'msg': '创建用户成功!'}
        return Response(res)

class AppView(APIView):
    def get(self, request, id=None):
        if id:
            obj = App.objects.get(id=id)
            ser = AppSerializer(obj)
        else:
            queryset = App.objects.all()
            ser = AppSerializer(queryset, many=True)
        res = {'code': 200, 'msg': '获取成功!', 'data': ser.data}
        return Response(res)
    def post(self, request):
        ser = AppSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        res = {'code': 200, 'msg': '创建用户成功!'}
        return Response(res)

class ServerView(APIView):
    def get(self, request, id=None):
        if id:
            obj = Server.objects.get(id=id)
            ser = ServerSerializer(obj)
        else:
            queryset = Server.objects.all()
            ser = ServerSerializer(queryset, many=True)
        res = {'code': 200, 'msg': '获取成功!', 'data': ser.data}
        return Response(res)
    def post(self, request):
        ser = ServerSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        res = {'code': 200, 'msg': '创建用户成功!'}
        return Response(res)
  1. 定义路由

from django.urls import re_path
from . 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. 添加测试数据

创建项目:
from Association_table.models import Project, App, Server
Project.objects.create(name="电商")
Project.objects.create(name="教育")
创建应用并指定项目:
project_obj = Project.objects.get(name="电商")
App.objects.create(name="portal", project=project_obj)
App.objects.create(name="gateway", project=project_obj)
创建服务器:
Server.objects.create(hostname="test1", ip="192.168.31.10")
Server.objects.create(hostname="test2", ip="192.168.31.11")
将应用部署到服务器:
app_obj = App.objects.get(name="portal")
server_obj = Server.objects.get(hostname="test1")
server_obj.app.add(app_obj)

7 序列化器返回是当前模型中的字段,如果字段是外键时,返回的是外键对应的id,如下图所示

对于这种情况有两种方法可以显示外键对应的详细信息

  • 定义字段为外键对应序列化类:例如project=ProjectSerializer(read_only=Ture),该方法适合针对某个外键字段。

class AppSerializer(serializers.ModelSerializer):
project = ProjectSerializer(read_only=True) # 一对多,返回关联的项目详情
class Meta:
model = App
fields = "__all__"
  • 序列化类中Meta类启用dpth:深度获取关联表数据,这种对所有外键都会显示

class AppSerializer(serializers.ModelSerializer):
class Meta:
model = App
fields = "__all__"
depth = 1

修改后如下图就可以显示外键对应的详细值

SerializerMethodField

SerializerMethodField可以在不修改数据模型的前提下,增加API字段

DRF序列器默认返回数据模型中已存在资源,如果想新增返回字段或者二次处理,则需要用用到SerializerMethodFiled

#实例给项目API增加一个字段,这个字段数据可以从别的表中获取
class ProjectSerializer(serializers.ModelSerializer):
    app_acount = serializers.SerializerMethodField()
    class Meta:
        model = Project
        fields = "__all__"
def get_app_acount(self,obj):
    return len(obj.app_set.all())
序列化和反序列化的行为:
  • to_internal_value():处理反序列化的输入数据,自动转换Python对象,方便处理

  • to_representation():处理序列化数据的输出。

什么时候需要用到反序列化的行为?

当提交API数据与序列化器要求的格式不符合时,序列化就会抛出错误,这个时候就可以使用to_internal_value()方法来提取符合序列化器要求的数据格式

例如:前端提交一个创建新项目的数据

{

"data": {

"id": 3,

"name": "大数据"

},

"extra_data":{

"count": 123

}

}

如下在序列化器中将符合序列化器的data数据使用to_internal_value方法重写后,就可以正常创建了

class ProjectSerializer(serializers.ModelSerializer):
    app_acount = serializers.SerializerMethodField()
    class Meta:
        model = Project
        fields = "__all__"
    def get_app_acount(self,obj):
        return len(obj.app_set.all())

     def to_internal_value(self, data):
         # data是前端提交未验证的数据
         data = data['data']
         return super().to_internal_value(data)

什么时候用到序列化行为?

当需要给返回的数据添加一个统计应用数量的字段时

class ProjectSerializer(serializers.ModelSerializer):
    #app_acount = serializers.SerializerMethodField()
    class Meta:
        model = Project
        fields = "__all__"

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值