61. drf之drf安装_使用_request_response_序列化组件
1. drf安装
1.1 使用django4版本
当前django版本为3.2.12

django4.2.2替换3.2.12

1.2 安装drf
pip install djangorestframework


mysql必须是8.0及以上,需要将之前的5.7.44升级
卸载mysql5.7.44与安装8.0参考mysql安装卸载文档

book表:id、name、price字段
5个接口:增一条、删一条、修改一条、查询一条、查询所有
2. drf使用
2.1 前置-新建drf项目

2.2 创建视图(View)
在应用app01的views.py中
之前django继承view
from django.views import View
drf继承APIView
from django.shortcuts import render, HttpResponse
# Create your views here.
from rest_framework.views import APIView
class TestView(APIView):
def get(self, request):
return HttpResponse("from TestView function get")
2.3 配置URL路由
先配置项目的总路由
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/app01/', include('app01.urls')), # api/v1/的含义是符合restful规范
]
在应用app01的urls.py中,定义drf的url路由
from django.contrib import admin
from django.urls import path
from .views import TestView
urlpatterns = [
path('test/', TestView.as_view()),
]

3. 新的request对象和response
3.1 request
[1] 查看request对象
drf项目只要继承了APIView的视图类,request对象就发生改变
type(request)查看request对象
class TestView(APIView):
def get(self, request):
print(type(request))
return HttpResponse("from TestView function get")
View的request对象:<class 'django.core.handlers.wsgi.WSGIRequest'>
APIView的request对象:<class 'rest_framework.request.Request'>
[2] 旧的属性和方法(View的request)
request对象本质是http请求
request.method
request.POST
request.GET
request.FILES
request.body
request.get_full_path()
request.META 字典
客户端类型:HTTP_USER_AGENT
客户端地址:remote_addr
app01的views.py中
from django.shortcuts import render, HttpResponse
# Create your views here.
from django.views import View
class TestView(View):
def get(self, request):
print(request.META)
return HttpResponse("from TestView function get")


[2] 新的属性和方法(APIView的request)
用起来和旧的一样,兼容旧的
多的:request.data、request.query_params
request.data:
只要在请求体body的数据,无论什么编码格式、无论什么请求方式,都可以从request.data获取
继承 APIView 后,无论是post请求还是 get请求,获取数据都是从 data 中获取
原来的request.POST中还有数据,但是数据类型支持的没有data全,比如json格式的数据
urlencoded,form-data:是QueryDict的对象
json:是普通字典对象
但是,都当字典用即可
取文件数据还是从 FILES 中取
取其他的属性(request.method/request/path...),和原来的一样
(1)post请求无法发送json格式数据
app01的views.py中
class TestView(APIView):
def post(self, request):
print(request.POST)
return HttpResponse("from TestView function post")
发送post请求,格式为urlencoded

post请求可以发送urlencoded格式数据

发送post请求,格式为json

post请求无法发送json格式的数据

(2)request.data可以发送json格式数据
app01的views.py中
class TestView(APIView):
def post(self, request):
print(request.data)
return HttpResponse("from TestView function post")
request.data可以发送json格式的数据


(3)request.query_params查询参数与request.GET等价
app01的views.py中
class TestView(APIView):
def post(self, request):
print(request.data)
print(request.GET is request.query_params)
return HttpResponse("from TestView function post")


request.query_params为了迎合restful规范中的请求地址带查询条件
3.2 response
drf的响应统一使用Response,不再使用四件套render、redirect、HttpResponse、JsonResponse
Response等同于:HttpResponse+JsonResponse,可以放字符串、字典、列表
app01的views.py中
from rest_framework.views import APIView
from rest_framework.response import Response
class TestView(APIView):
def post(self, request):
print(request.data)
print(request.GET is request.query_params)
return Response("from TestView function post")
def get(self, request):
print(request.META)
return Response("from TestView function get")
(1)postman可以正常访问


(2)浏览器访问报错,模板不存在

(3)解决报错
在settings.py中,注册rest_framework这个app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'rest_framework',
]
注册app之后浏览器访问不再报错

(4)自定义响应状态码
Response('......', status=201)
默认响应状态码200

自定义响应状态码201
app01的views.py中
class TestView(APIView):
def get(self, request):
print(request.META)
return Response("from TestView function get")
def post(self, request):
print(request.data)
return Response("from TestView function post", status=201)

(5)自定义响应头
Response('......', headers={'x': 'y'})
class TestView(APIView):
def get(self, request):
print(request.META)
return Response("from TestView function get")
def post(self, request):
print(request.data)
return Response("from TestView function post", headers={'height': 1.9})

(6)总结
views.py中点击Response即可看到详细参数
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
data=None 响应体:可以传 字典、列表、字符串
headers=None 响应头
status=None http响应状态码drf封装了所有常量
HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_102_PROCESSING = 102
HTTP_103_EARLY_HINTS = 103
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
了解知识点:
exception=False 异常
content_type=None 响应编码格式,一般不动,都用json
template_name=None 指定使用浏览器访问返回的模板,没写用默认模板
4. 序列化类
4.1 概念
【1】介绍
DRF(Django REST framework)是一个用于构建基于 Django 的 Web API 的强大框架。
在 DRF 中,序列化组件是其中一个核心组件,用于在 API 请求和响应中处理数据的转换和验证。
序列化组件的主要功能是将复杂的数据结构(例如模型对象)转换为可以序列化(序列化为 JSON、XML 等格式)和传输的数据,并且能够根据所需的数据结构对传入的数据进行反序列化,还原为程序可操作的对象。
【2】重要特点和用法:
定义序列化类:在 DRF 中,需要创建一个继承自 serializers.Serializer 或 serializers.ModelSerializer 的序列化类。这个类定义了要序列化和反序列化的字段和规则。
字段类型:序列化类中的字段用于指定数据结构中的字段以及其对应的类型。DRF 提供了多种字段类型,如字符串字段 (CharField)、整数字段 (IntegerField)、日期时间字段 (DateTimeField) 等。
嵌套关系:序列化类支持嵌套关系的处理,可以通过使用 Serializer 字段或 ModelSerializer 字段来表示两个模型之间的关联关系。
验证和转换:序列化组件提供了数据验证和转换的功能,可以在反序列化时验证输入数据的有效性,并对输入数据进行转换,使其符合定义的字段规则。
增加额外的字段和逻辑:在序列化类中,可以添加额外的字段和自定义方法,来处理复杂的业务逻辑,如计算属性和关联模型的反向查询等。
序列化输出:序列化组件将序列化类中定义的字段转换为指定的输出格式(JSON、XML 等),方便进行数据传输和展示。
反序列化输入:序列化组件能够将传入的数据反序列化为程序可操作的对象,以便进行进一步的处理和保存。
【3】小结
序列化
序列化器会把模型对象(queryset,单个对象)转换成字典
经过response以后变成json字符串
反序列化
把客户端发送过来的数据,经过request.data以后变成字典
序列化器可以把字典转成模型
反序列化
完成数据校验功能
4.2 步骤
1. 自定义一个类(序列化类),继承基类(serializer.Serializer)
2. 在序列化类中写字段
3. 在视图类中,实例化得到的对象,可以进行数据校验 --序列化、校验
4. 在视图类中,实例化得到的对象,可以保存或修改MySQL中的数据 --反序列化
4.3 序列化基本使用
[1] 准备数据模型
准备:MySQL中新建drf01_db库,settings.py中增加配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'drf01_db',
'HOST': 'localhost',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '123456789',
}
}
app01的models.py中定义模型表,将模型表迁移至数据库
class Student(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
school = models.CharField(max_length=32)
添加数据

[2] 制作序列化器
在app01新建serializer.pyfrom rest_framework import serializers
class StudentSerializer(serializers.Serializer):
# 写要序列化的字段,针对Student表不一定需要将4个字段都序列化
id = serializers.IntegerField()
name = serializers.CharField()
age = serializers.IntegerField()
school = serializers.CharField()
[3] 使用序列化器--查询所有数据
app01的views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Student
from .serializer import StudentSerializer
class StudentView(APIView):
def get(self, request):
students = Student.objects.all() # 1.取出所有数据
# 2.序列化---drf提供的序列化类来完成---序列化得到对象时,需要传参数
# instance : 实例(对象)
# data : 数据
# many=True : 如果是queryset对象,必须加True
# many=False : 如果是.first(),则为False,一般不写,默认不写是 False
serializer1 = StudentSerializer(instance=students, many=True)
# 3.返回给前端
return Response(serializer1.data) # 括号里即为序列化后的数据
app01的urls.py
from django.urls import path
from .views import StudentView
urlpatterns = [
path('student/', StudentView.as_view()),
]
项目的urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/app01/', include('app01.urls')), # api/v1/的含义是符合restful规范
]
后端返回给前端的数据

[4] 使用序列化器--查询一条数据
app01的views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Student
from .serializer import StudentSerializer
class StudentDetailView(APIView):
def get(self, request, pk):
# 1.根据id,取出数据
student = Student.objects.filter(pk=pk).first()
# 2.序列化
serializer1 = StudentSerializer(instance=student)
# 3.返回给前端
return Response(serializer1.data)
app01的urls.py
from django.urls import path
from .views import StudentView, StudentDetailView
urlpatterns = [
path('student/', StudentView.as_view()),
path('student/<int:pk>/', StudentDetailView.as_view()),
]
后端返回给前端的数据


前端展示的字段与序列化器中的字段保持一致
4.4 序列化组件常用字段和参数
[1] 常用字段
序列化组件中的字段与models.py中的字段类一一对应
| 字段 | 字段构造方式 | 详解 |
|---|---|---|
| CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) | 字符字段用于存储短文本数据。max_length指定字符的最大长度,min_length指定最小长度。allow_blank指定是否允许为空值。trim_whitespace指定是否在保存数据前去除首尾的空格。 |
| IntegerField | IntegerField(max_value=None, min_value=None) | 整数字段用于存储整数值。max_value指定最大值,min_value指定最小值。 |
| FloatField | FloatField(max_value=None, min_value=None) | 浮点数字段用于存储浮点数值。max_value指定最大值,min_value指定最小值。 |
| DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 | 十进制字段用于存储精确的十进制数值。max_digits指定最多位数,decimal_places指定小数点位置。coerce_to_string指定是否将值强制转化为字符串形式。max_value指定最大值,min_value指定最小值。 |
| DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) | 日期时间字段用于存储日期和时间。format参数指定日期时间的输出格式,input_formats参数指定输入格式。 |
| DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) | 日期字段用于存储日期。format参数指定日期的输出格式,input_formats参数指定输入格式。 |
| TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) | 时间字段用于存储时间。format参数指定时间的输出格式,input_formats参数指定输入格式。 |
| ListField | ListField(child=, min_length=None, max_length=None) | 列表字段用于存储和验证列表类型的数据。child参数指定列表中元素的类型,min_length指定最小长度,max_length指定最大长度。 |
| DictField | DictField(child=) | 字典字段用于存储和验证字典类型的数据。child参数指定字典中value的类型。 |
如果不知道models和Serializer如何对应,序列化组件的字段统一用 CharField
[2] 字段参数
序列化组件中的字段的参数,作用是反序列化校验用
只针对于:CharField
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
只针对于:IntegerField
max_value 最小值
min_value 最大值
只针对于:DateTimeField
format:序列化时,显示的格式
DateTimeField(format='Y年m月d日')
所有字段类都用
required:是否必填
default :反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
两个重点
read_only 表明该字段仅用于序列化输出(只读),默认False
write_only 表明该字段仅用于反序列化输入校验(只写),默认False
4.5 反序列化
[1] 反序列化之保存
(1) 新增数据
总路由
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/app01/', include('app01.urls')), # api/v1/的含义是符合restful规范
]
app01的路由
from django.urls import path
from .views import StudentView, StudentDetailView
urlpatterns = [
path('student/', StudentView.as_view()),
path('student/<int:pk>/', StudentDetailView.as_view()), # 用于修改,这里用不到
]
app01的models.py
from django.db import models
# Create your models here.
class Student(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
school = models.CharField(max_length=32)
app01的views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Student
from .serializer import StudentSerializer
class StudentView(APIView):
def post(self, request):
# 1.取出前端传入的请求体中的数据(json、urlencoded、form-data)
# 2.序列化类实例化得到对象,反序列化不需要传入instance
serializer1 = StudentSerializer(data=request.data) # request.data即为前端传入的数据
# 3.反序列化校验
# 4.保存到数据库
# 5.返回给前端
if serializer1.is_valid():
# 不知道要保存到哪个表中,要在序列化组件中重写create方法
# serializer1.save如果是新增,会触发serializer.create方法的运行
serializer1.save()
return Response(serializer1.data) # 返回给前端新增的对象
else: # 校验不通过
return Response(serializer1.errors)
app01的serializer.py
from rest_framework import serializers
from .models import Student
class StudentSerializer(serializers.Serializer):
# 写要序列化的字段,针对Student表不一定需要将4个字段都序列化
id = serializers.IntegerField()
name = serializers.CharField()
age = serializers.IntegerField()
school = serializers.CharField()
def create(self, validated_data):
# validated_data是字典,即前端传入经过校验的数据,保存到指定的表中
# **validated_data对数据进行解包
student = Student.objects.create(**validated_data)
# 返回新增的对象,后期调用serializer.data,会使用它进行序列化,即返回给视图函数
return student
增加一条json数据


总结:
1.定义序列化器
2.在序列化器中写字段和字段参数,用于校验
3.在视图类中使用序列化器
4.序列化器中重写create函数
(2) 修改数据
指定字段逐个修改数据
序列化组件的update函数,其它与多字段方法相同
instance.name = validated_data.get('name')
instance.age = validated_data.get('age')
instance.school = validated_data.get('school')
多字段一起修改数据
app01的views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Student
from .serializer import StudentSerializer
class StudentDetailView(APIView):
def put(self, request, pk):
# 1.根据id,查询需要修改的对象
student = Student.objects.filter(pk=pk).first()
# 2.获取前端传入的数据,使用data数据对instance对象进行修改
# 只有instance为序列化,只有data为反序列化的新增,这里两者都有
serializer1 = StudentSerializer(data=request.data, instance=student)
# 3.校验数据
# 4.保存到数据库中
if serializer1.is_valid():
# 需要在序列化组件中重写update方法
serializer1.save()
return Response(serializer1.data)
else:
return Response(serializer1.errors)
app01的serializer.py
from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
# 写要序列化的字段,针对Student表不一定需要将4个字段都序列化
id = serializers.IntegerField()
name = serializers.CharField()
age = serializers.IntegerField()
school = serializers.CharField()
def update(self, instance, validated_data):
"""
:param instance: 待修改的对象
:param validated_data:前端传入,校验过后的数据
:return:
"""
for k in validated_data:
# 利用反射方法 等同于instance.k=validated_data.get(k)
setattr(instance, k, validated_data.get(k))
instance.save()
return instance # 返回修改的对象



总结:
1.定义序列化器
2.在序列化器中写字段和字段参数,用于校验
3.在视图类中使用序列化器
4.序列化器中重写update函数
(3) save方法源码
在视图类中,无论是新增还是修改,都是调用序列化类的 save() 方法
底层实现逻辑是根据 instance 判断需要做出的对应的方法
def save(self, **kwargs):
# 根据传入的 instance 对象,进行方式的判断 update/create
# 如果是 update 方法 需要传入修改前和修改后的数据
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
# 如果是 create 需要传入新增的数据
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
return self.instance
[2] 使用新增进行反序列化之校验
反序列化有三层校验:
字段自身:序列化组件中字段的参数,min_length、max_length、required
局部钩子:序列化组件中的函数,函数名必须是 validate_字段名
全局钩子:序列化组件中的函数,函数名必须是 validate
步骤:重新迁移student模型表至数据库,内容为空
(1) 字段自身校验
app01的urls.py
from django.urls import path
from .views import StudentView
urlpatterns = [
path('student/', StudentView.as_view()),
]
app01的models.py
class Student(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
school = models.CharField(max_length=32)
序列化组件app01的serializer.py
from rest_framework import serializers
from .models import Student
class StudentSerializer(serializers.Serializer):
# 写要序列化的字段,针对Student表不一定需要将4个字段都序列化
id = serializers.IntegerField()
name = serializers.CharField(min_length=3, max_length=10) # 字段自身校验
age = serializers.IntegerField(min_value=1, max_value=125)
school = serializers.CharField()
app01的views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializer import StudentSerializer
class StudentView(APIView):
def post(self, request):
serializer1 = StudentSerializer(data=request.data)
if serializer1.is_valid():
serializer1.save()
return Response(serializer1.data)
else:
return Response(serializer1.errors)
测试

setting.py中对django进行汉化
修改前
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
修改后
LANGUAGE_CODE = "zh-hans"
TIME_ZONE = "Asia/Shanghai"
USE_I18N = True
USE_TZ = True
汉化之后的返回为汉字

(2) 局部钩子校验
局部钩子用于给某个字段进行校验
必须先通过字段自身校验才能进行局部钩子校验
代码示例:name不能以qw开头
序列化组件app01的serializer.py中
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
class StudentSerializer(serializers.Serializer):
# 写要序列化的字段,针对Student表不一定需要将4个字段都序列化
id = serializers.IntegerField()
name = serializers.CharField(min_length=3, max_length=10) # 字段自身校验
age = serializers.IntegerField(min_value=1, max_value=115)
school = serializers.CharField()
def validate_name(self, v):
if v.startswith('qw'):
# 如果以qw开头,则抛出异常
raise ValidationError('姓氏不能是qw')
else:
return v

(3)全局钩子校验
全局钩子用于给多个字段进行组合校验
代码示例:name和school的前两个字符不能一样
序列化组件app01的serializer.py中
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
class StudentSerializer(serializers.Serializer):
# 写要序列化的字段,针对Student表不一定需要将4个字段都序列化
id = serializers.IntegerField()
name = serializers.CharField(min_length=3, max_length=10) # 字段自身校验
age = serializers.IntegerField(min_value=1, max_value=115)
school = serializers.CharField()
def validate_name(self, v):
if v.startswith('qw'):
# 如果以qw开头,则抛出异常
raise ValidationError('姓氏不能是qw')
else:
return v
def validate(self, attrs): # attrs是前端传入,经过之前字段自身校验和局部钩子校验的数据
# 取出name和school的前两个字符
name1 = attrs.get('name')[:2]
school1 = attrs.get('school')[:2]
if name1 == school1:
raise ValidationError('name和school的前两个字符不能一样')
else:
return attrs


浙公网安备 33010602011771号