61. drf之drf安装_使用_request_response_序列化组件

1. drf安装

1.1 使用django4版本

当前django版本为3.2.12

image

django4.2.2替换3.2.12

image

1.2 安装drf

pip install djangorestframework

image

image

mysql必须是8.0及以上,需要将之前的5.7.44升级

卸载mysql5.7.44与安装8.0参考mysql安装卸载文档

image

book表:id、name、price字段

5个接口:增一条、删一条、修改一条、查询一条、查询所有

2. drf使用

2.1 前置-新建drf项目

image

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()),
]

image

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")

image

image

[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

image

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

image

发送post请求,格式为json

image

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

image

(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格式的数据

image

image

(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")

image

image

 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可以正常访问

image

image

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

image

(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之后浏览器访问不再报错

image

(4)自定义响应状态码

Response('......', status=201)

默认响应状态码200

image

自定义响应状态码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)

image

(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})

image

(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)

添加数据

image

[2] 制作序列化器

在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()

[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规范
]

后端返回给前端的数据

image

[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()),
]

后端返回给前端的数据

image

image

前端展示的字段与序列化器中的字段保持一致

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数据

image

image

总结:

  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  # 返回修改的对象

image

image

image

总结:

  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)

测试

image

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

 

汉化之后的返回为汉字

image

(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

image

(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

image

 

posted @ 2026-07-29 00:15  pythondjango  阅读(5)  评论(0)    收藏  举报