Django REST Framework入门之序列化器

文章目录

  • 一、概述
  • 二、安装
  • 三、序列化与反序列化介绍
  • 四、之前常用三种序列化方式
    • json
    • Django内置Serializers模块
    • Django内置JsonResponse模块
  • 五、DRF序列化器
    • 序列化器工作流程
      • 序列化(读数据)
      • 反序列化(写数据)
    • 序列化器常用方法与属性
    • 序列化器参数
    • 扩展验证规则
      • 局部钩子:validate_字段名(self, 字段值)
      • 全局钩子:validate(self, 所有校验的数据字典)
    • 序列化器支持三种类型:
      • Serializer
        • 创建应用myapp
        • 注册myapp
        • 定义数据模型并同步数据库
        • 定义序列化器
        • 视图里使用序列化器
        • 定义路由
        • 启动项目
        • 实现POST方法
        • 获取单个用户
        • 更新用户
        • 删除用户
      • `ModelSerializer[推荐使用]`
        • Meta类常用属性
        • 示例
      • HyperModelSerializer
    • 关联表显示
      • 定义数据模型(myapp/models.py)
      • 定义序列化器(myapp/serializers.py)
      • 定义视图(myapp/views.py)
      • 定义路由(myapp/urls.py)
      • 创建数据库表
      • 启动Django项目
      • 插入测试数据
      • 显示外键对应的详细信息
        • 方法一
        • 方法二
    • 序列化器:SerializerMethodField
      • 示例:给项目API增加一个字段,这个字段数据可从别的表中获取
    • 改变序列化和反序列化的行为
      • 示例1:
      • 示例2:希望给返回的数据添加一个统计应用数量的字段
  • 参考


一、概述

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

能简化序列化及开发REST API视图的代码,大大提高REST API的开发速度;提供灵活的路由API,内置了强大的认证和授权机制

二、安装

Django REST framework 最新版使用要求
在这里插入图片描述

pip install djangorestframework

在settings.py文件的INSTALLED_APPS添加rest_framework
在这里插入图片描述

三、序列化与反序列化介绍

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

四、之前常用三种序列化方式

json

import json
# 序列化
computer = {"主机":5000,"显示器":1000,"鼠标":60,"键盘":150}
json.dumps(computer)
# 反序列化
json.loads(json_obj)

Django内置Serializers模块

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

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

Django内置JsonResponse模块

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

res = {"code": 200, msg: "查询成功"}
return JsonResponse(res)

五、DRF序列化器

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

序列化器工作流程

序列化(读数据)

视图里通过ORM从数据库获取数据查询集对象 -> 传入序列化器-> 序列化器将数据进行序列化 -> 调用序列化器的.data获取数据 -> 返回前端

反序列化(写数据)

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

序列化器常用方法与属性

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

序列化器参数

在这里插入图片描述
示例:

class UserSerializer(serializers.Serializer):# 这里的字段必须与使用模型的字段对应id = serializers.IntegerField(read_only=True)name = serializers.CharField(max_length=30,error_messages={ # 设置错误提示"blank": "请输入姓名","required": "该字段必要","max_length": "字符长度不超过30",})

扩展验证规则

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

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

class UserSerializer(serializers.Serializer):…………# 局部钩子# 姓名不能包含数字def validate_name(self, attrs): # attrs是该字段的值from re import findallif findall('\d+', attrs):raise serializers.ValidationError("姓名不能包含数字")else:return attrs

在视图函数里面通过如下方法查看异常信息

user_ser = UserSerializer(data=request.data)
print(user_ser.errors)

效果如下:
在这里插入图片描述

全局钩子:validate(self, 所有校验的数据字典)

class UserSerializer(serializers.Serializer):…………# 全局钩子def validate(self, attrs):  # attrs是所有字段组成的字典sex = attrs.get("sex")if sex not in ['男','女']:raise serializers.ValidationError("性别只能为男或者女")else:return attrs

序列化器支持三种类型:

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

Serializer

创建应用myapp
python manage.py startapp myapp
注册myapp

在settings.py文件的INSTALLED_APPS添加myapp
在这里插入图片描述

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

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=10)age = models.IntegerField()

python manage.py makemigrations
python manage.py migrate

定义序列化器

创建myapp_api/serializers.py

from rest_framework import serializersclass UserSerializer(serializers.Serializer):# 这里的字段必须与使用模型的字段对应id = serializers.IntegerField()name = serializers.CharField(max_length=30)city = serializers.CharField(max_length=30)sex = serializers.CharField(max_length=10)age = serializers.IntegerField()
视图里使用序列化器
from myapp.models import User   # 导入模型
from .serializers import UserSerializer # 导入序列化器
from rest_framework.views import APIView
from rest_framework.response import Responseclass UserView(APIView):def get(self, requset):queryset = User.objects.all()   # 获取所有用户# 调用序列化器将queryset对象转换为jsonuser_ser = UserSerializer(queryset, many=True)  # 如果序列化多条数据,需要指定many=Truereturn Response(user_ser.data)  # 从.data属性获取序列化结果
定义路由

test01(项目名)/urls.py

from django.contrib import admin
from django.urls import path,re_path,includeurlpatterns = [path('admin/', admin.site.urls),re_path('myapp/', include('myapp.urls')),
]

myapp_api/urls.py

from django.urls import re_path
from myapp import viewsurlpatterns = [re_path('^api/user/$', views.UserView.as_view()),
]
启动项目

访问地址:http://127.0.0.1:8001/myapp/api/user/,可以查看数据
在这里插入图片描述
现在数据库是空的,下面写一个POST方法,来实现数据的创建

实现POST方法

myapp/views.py,在class UserView的get方法下面增加post方法

def post(self, request):user_ser = UserSerializer(data=request.data)    # 调用序列化器将传入的数据反序列化,转换为Python对象if user_ser.is_valid():     # 验证数据格式是否正确user_ser.save()         # 保存数据到数据库msg = '创建用户成功'code = 200else:msg = '数据格式不正确'code = 400res = {'code': code, 'msg': msg}return Response(res)

在myapp/serializers.py下面增加如下方法

from myapp.models import User
def create(self, validated_data):   # validated_data为提交的JSON数据return User.objects.create(**validated_data)

在这里插入图片描述
刷新页面,发现下面多了个输入框,右下角有POST按钮
输入JSON数据,点击POST
在这里插入图片描述
返回创建成功
在这里插入图片描述
再次查看发现多了条数据
在这里插入图片描述
再添加几条数据,结果如下
在这里插入图片描述
上面的方法是查看所有用户,那么如何查看单个用户呢?

获取单个用户

修改myapp/views.py中的get方法为:

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

myapp/urls.py增加如下路由

re_path('^api/user/(?P<pk>\d+)/$', views.UserView.as_view()),

在这里插入图片描述
效果
在这里插入图片描述

更新用户

myapp/views.py,在class UserView的get方法下面增加put方法

def put(self, request, pk=None):user_obj = User.objects.get(id=pk)  # 从数据库查找现有的值#调用序列化器传入已有对象和提交的数据user_ser = UserSerializer(instance=user_obj, data=request.data)if user_ser.is_valid():user_ser.save()msg = '更新用户成功'code = 200else:msg = '更新用户失败,数据格式不对'code = 400res = {'code': code, 'msg': msg}return Response(res)

在myapp/serializers.py下面增加如下方法

def update(self, instance, validated_data):     # instance为当前操作的对象,validated_data为提交JSON数据instance.name = validated_data.get('name')instance.city = validated_data.get('city')instance.sex = validated_data.get('sex')instance.age = validated_data.get('age')instance.save()return instance

实际效果
在这里插入图片描述

删除用户

myapp/views.py,在class UserView的get方法下面增加delete方法

def delete(self, request, pk=None):user_obj = User.objects.get(id=pk)try:user_obj.delete()msg = '用户删除成功'code = 200except Exception as e:msg = '用户删除失败'code = 400res = {'code': code, 'msg': msg}return Response(res)

效果
在这里插入图片描述

ModelSerializer[推荐使用]

ModelSerializer 类型不需要自定义字段映射和定义create、update方法,使用起来方便很多!

Meta类常用属性

• fields:显示所有或指定字段
• exclude:排除某个字段,元组格式,不能与fields同时用
• read_only_fields:只读字段,即只用于序列化,不支持修改
• extra_kwargs:添加或修改原有的字段参数,字典格式
• depth:根据关联的数据递归显示,一般是多表

示例
class UserSerializer(serializers.ModelSerializer):class Meta:model = User    # 指定数据模型fields = '__all__'  # 显示所有字段#exclude = ('id', )  # 排除字段read_only_fields = ('id', )extra_kwargs = {'name': {'max_length': 30, 'requierd': True},'city': {'max_length': 10, 'requierd': True},'age': {'max_length': 30, 'requierd': True},'sex': {'mix_value': 16, 'max_value': 100, 'requierd': True},}

HyperModelSerializer

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

# 更改序列化器
class UserSerializer(serializers.HyperlinkedModelSerializer):class Meta:model = Userfields = "__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")

关联表显示

例如:应用发布系统项目涉及表
一对多:一个项目有多个应用,一个应用只能属于一个项目
多对多:一个应用部署到多台服务器,一个服务器部署多个应用
在这里插入图片描述

定义数据模型(myapp/models.py)

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)   # 多对多

定义序列化器(myapp/serializers.py)

from rest_framework import serializers
from myapp.models import Project, App, Serverclass ProjectSerializer(serializers.ModelSerializer):class Meta:model = Projectfields = "__all__"class AppSerializer(serializers.ModelSerializer):class Meta:model = Appfields = "__all__"class ServerSerializer(serializers.ModelSerializer):class Meta:model = Serverfields = "__all__"

定义视图(myapp/views.py)

from rest_framework.views import APIView
from rest_framework.response import Response
from myapp.models import Project, App, Server
from .serializers import ProjectSerializer, AppSerializer, ServerSerializerclass ProjectView(APIView):def get(self, request):queryset = Project.objects.all()  # 获取所有用户project_ser = ProjectSerializer(queryset, many=True)res = {'code': 200, 'msg': '获取用户成功', 'data': project_ser.data}return Response(res)  # 从.data属性获取序列化结果def post(self, requset):project_ser = ProjectSerializer(data=requset.data)project_ser.is_valid(raise_exception=True)project_ser.save()return Response(data=project_ser.data)class AppView(APIView):def get(self, request):queryset = App.objects.all()  # 获取所有用户app_ser = AppSerializer(queryset, many=True)res = {'code': 200, 'msg': '获取用户成功', 'data': app_ser.data}return Response(res)  # 从.data属性获取序列化结果def post(self, requset):app_ser = AppSerializer(data=requset.data)app_ser.is_valid(raise_exception=True)app_ser.save()return Response(data=app_ser.data)class ServerView(APIView):def get(self, request):queryset = Server.objects.all()  # 获取所有用户server_ser = AppSerializer(queryset, many=True)res = {'code': 200, 'msg': '获取用户成功', 'data': server_ser.data}return Response(res)  # 从.data属性获取序列化结果def post(self, requset):server_ser = ServerSerializer(data=requset.data)server_ser.is_valid(raise_exception=True)server_ser.save()return Response(data=server_ser.data)

定义路由(myapp/urls.py)

from django.urls import re_path
from myapp import viewsurlpatterns = [re_path('^api/project/$', views.ProjectView.as_view()),re_path('^api/app/$', views.AppView.as_view()),re_path('^api/server/$', views.ServerView.as_view()),
]

创建数据库表

python manage.py makemigrations
python manage.py migrate

启动Django项目

插入测试数据

打开python控制台
在这里插入图片描述

#创建项目:
from myapp.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)

结果如下:
在这里插入图片描述

显示外键对应的详细信息

序列化器返回的是当前模型中的字段,如果字段是外键时,返回的是外键对应id。如下图所示
在这里插入图片描述
有两种解决方法

方法一

定义字段为外键对应序列化类,这种适合针对某个外键字段
例如:

project=ProjectSerializer(read_only=True)	# 一对多
app = AppSerializer(many=True) # 多对多

在这里插入图片描述

方法二

序列化类中Meta类启用depth:深度获取关联表数据,这种所有外键都会显示出来
在这里插入图片描述
效果如下:
在这里插入图片描述

序列化器:SerializerMethodField

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

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

class ProjectSerializer(serializers.ModelSerializer):app_count = serializers.SerializerMethodFieldclass Meta:model = Projectfields = "__all__"# get_字段名def get_app_count(self, obj):return len(obj.app_get.all())

改变序列化和反序列化的行为

可以通过重写下面两个方法改变序列化和反序列化的行为:
• to_internal_value():处理反序列化的输入数据,自动转换Python对象,方便处理。
• to_representation():处理序列化数据的输出

示例1:

如果提交API的数据与序列化器要求的格式不符合,序列化器就会出现错误。
这时就可以重写to_internal_value()方法只提取出我们需要的数据
在这里插入图片描述

示例2:希望给返回的数据添加一个统计应用数量的字段

在这里插入图片描述

参考

https://www.aliangedu.cn/course/learn?cid=20&sid=10&pid=2197

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/637555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flink(十四)【Flink SQL(中)查询】

前言 接着上次写剩下的查询继续学习。 Flink SQL 查询 环境准备&#xff1a; # 1. 先启动 hadoop myhadoop start # 2. 不需要启动 flink 只启动yarn-session即可 /opt/module/flink-1.17.0/bin/yarn-session.sh -d # 3. 启动 flink sql 的环境 sql-client ./sql-client.sh …

力扣每日一题---1547. 切棍子的最小成本

//当我们将棍子分段之后&#xff0c;我们是不是想到了怎么组合这些棍子 //并且这些棍子有一个性质就是只能与相邻的进行组合 //暴力搜索的话复杂度很高 //在思考暴力搜索的时候&#xff0c;我们发现一个规律 //比如棍子长度1 2 1 1 2 //那么与最后一个2组合的棍子有&#xff0c…

【大数据分析与挖掘技术】Mahout推荐算法

目录 一、推荐的定义与评估 &#xff08;一&#xff09;推荐的定义 &#xff08;二&#xff09;推荐的评估 二、Mahout中的常见推荐算法 &#xff08;一&#xff09;基于用户的推荐算法 &#xff08;二&#xff09;基于物品的推荐算法 &#xff08;三&#xff09;基于S…

SQL注入实战:http报文包讲解、http头注入

一&#xff1a;http报文包讲解 HTTP(超文本传输协议)是今天所有web应用程序使用的通信协议。最初HTTP只是一个为获取基于文本的静态资源而开发的简单协议&#xff0c;后来人们以各种形式扩展和利用它.使其能够支持如今常见的复杂分布式应用程序。HTTP使用一种用于消息的模型:客…

NLP论文阅读记录 - 2021 | WOS 使用预训练的序列到序列模型进行土耳其语抽象文本摘要

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.相关工作2.1 预训练的序列到序列模型2.2 抽象文本摘要 三.本文方法3.1 总结为两阶段学习3.1.1 基础系统 3.2 重构文本摘要 四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结…

maven 基本知识/1.17

maven ●maven是一个基于项目对象模型(pom)的项目管理工具&#xff0c;帮助管理人员自动化构建、测试和部署项目 ●pom是一个xml文件&#xff0c;包含项目的元数据&#xff0c;如项目的坐标&#xff08;GroupId,artifactId,version )、项目的依赖关系、构建过程 ●生命周期&…

数据库性能优化的解决方案

目录​​​​​​​ 1、什么是数据库性能优化 1.1 数据库性能优化的概念 1.2 为何需要进行数据库性能优化 1.3 数据库性能优化的好处 2、数据库性能优化的基本原理 2.1 数据库查询优化 2.2 数据库索引优化 2.3 数据库表结构优化 2.4 数据库硬件优化 3、数据库查询优化…

OpenHarmony AI框架开发指导

一、概述 1、 功能简介 AI业务子系统是OpenHarmony提供原生的分布式AI能力的子系统。AI业务子系统提供了统一的AI引擎框架&#xff0c;实现算法能力快速插件化集成。 AI引擎框架主要包含插件管理、模块管理和通信管理模块&#xff0c;完成对AI算法能力的生命周期管理和按需部…

Tensorflow2 GPU版本-极简安装方式

Tensorflow2 GPU版本-极简安装方式&#xff1a; 1、配置conda环境加速 https://wtl4it.blog.csdn.net/article/details/135723095https://wtl4it.blog.csdn.net/article/details/135723095 2、tensorflow-gpu安装 conda create -n STZZWANG_TF2 tensorflow-gpu2.0

[AutoSar]BSW_OS 02 Autosar OS_STACK

目录 关键词平台说明一、 task stack1.1 Task stack 的共享1.2 task stack 的实际使用大小 二、ISR stack2.1 ISR stack 的共享 三、Single-stack&#xff08;单一栈&#xff09;和multi-stack &#xff08;多栈&#xff09;策略3.1 Single-stack3.2 multi-stack 四、Stack Che…

Datawhale 强化学习笔记(三)基于策略梯度(policy-based)的算法

文章目录 参考基于价值函数的缺点策略梯度算法REINFORCE 算法策略梯度推导进阶策略函数的设计离散动作的策略函数连续动作的策略函数 参考 第九章 策略梯度 之前介绍的 DQN 算法属于基于价值(value-based)的算法&#xff0c;基于策略梯度的算法直接对策略本身进行优化。 将策…

HackTheBox - Medium - Linux - BackendTwo

BackendTwo BackendTwo在脆弱的web api上通过任意文件读取、热重载的uvicorn从而访问目标&#xff0c;之后再通过猜单词小游戏获得root 外部信息收集 端口扫描 循例nmap Web枚举 feroxbuster扫目录 /api/v1列举了两个节点 /api/v1/user/1 扫user可以继续发现login和singup 注…

Java设计模式-抽象工厂模式(5)

大家好,我是馆长!从今天开始馆长开始对java设计模式的创建型模式中的单例模式、原型模式、工厂方法、抽象工厂、建造者的抽象工厂模式进行讲解和说明。 抽象工厂模式(Abstract Factory Pattern) 定义 是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类…

VScode新增设备实现无感接入(不需要输入密码)

VScode远程开发接入设备&#xff0c;默认是需要输入密码的&#xff0c;但是日常开发中刷新就需要重新输入密码&#xff0c;很烦人。配置ssh的RSA密钥后会&#xff0c;就可以直接系统级别验证接入&#xff0c;对开发人员来说验证步骤就透明了&#xff0c;实现无感接入&#xff0…

多线程

Linux系统的多线程 1. Linux线程概念1.1 什么是线程1.2 页表的概念1.2.1 一级页表的缺点1.2.2 二级页表 1.3 线程的优缺点1.4 线程异常1.5 线程用途1.6 Linux进程VS线程 2. Linux线程控制2.1 创建线程2.2 线程ID及地址空间布局2.3 线程终止2.3.1 线程函数处进行return2.3.2 使用…

Java安全 CC链1分析

Java安全之CC链1分析 什么是CC链环境搭建jdk下载idea配置创建项目 前置知识Transformer接口ConstantTransformer类invokerTransformer类ChainedTransformer类 构造CC链1CC链1核心demo1demo1分析 寻找如何触发CC链1核心TransformedMap类AbstractInputCheckedMapDecorator类readO…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-6 fieldset

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>fieldset</title> </head><body> <form action"#"><fieldset><legend>学生信息</legend>姓名&#xff1a;&…

2024PMP考试新考纲-【过程领域】近期典型真题和很详细解析(8)

华研荟继续为您分享【过程Process领域】的新考纲下的真题&#xff0c;今天来看几道关于风险方面的PMP真题&#xff0c;帮助大家体会和理解新考纲下PMP的考试特点和如何应用所学的知识和常识&#xff08;经验&#xff09;来解题&#xff0c;并且举一反三&#xff0c;一次性3A通过…

WordPress怎么去除jquery和CSS静态文件链接中的版本号?附2种方法

我们很多WordPress网站默认情况下所加载的jquery和CSS静态文件链接中都会带有相应的版本号&#xff0c;比如boke112百科使用的YIA主题&#xff0c;加载CSS文件时就会在链接地址后面加上?ver2.7&#xff0c;即是style.css?ver2.7 除了CSS文件会加上版本号外&#xff0c;加载主…

[小程序]样式与配置

一、外部样式导入 使用import加外部样式表的相对路径并以 ; 表示语句结束。 import "common.wxss"; 二、全局样式和局部样式 全局样式位于app.wxss中&#xff0c;会作用于整个项目中所有页面中。 局部样式位于对应的wxss文件中&#xff0c;仅作用于当前页面&#x…