DRF基础

DRF基础

DRF基础

【零】DRF在Django项目中的使用

【1】导入

# DRF需要使用pip install 安装
pip install djangorestframework
  • DRF(Django Rest Framework)是一个用于构建 Web API 的工具包,它是基于 Django 框架的一个第三方应用(app)
  • 在 Django 项目中,一个应用(app)通常是一个具有特定功能的模块,它包含了模型、视图、模板等组件,用于实现特定的功能或业务逻辑。

image-20240415161036714

【2】使用

  • 使用drf时,需要先在settings.py文件中进行注册app
# settings.py
INSTALLED_APPS = [
    ...
    'rest_framework'
]

【一】View

  • restful规范所需5个接口
    • 查询所有
    • 添加
    • 查询单条数据
    • 更新单条
    • 删除单条

【1】基于Django的View实现5个接口

image-20240415163008511

  • 预处理请求数据的装饰器代码

image-20240415170227132

  • 【注】该版本如果使用post请求,需要注释掉csrf中间件

【2】基于DRF.APIView + Response实现5个接口

  • 使用Django自带的View我们可以发现,其对请求数据的处理不够完善

  • 而在DRF中,其帮我们处理了请求数据,能够让我们可以通过【request.data】直接获取到三种编码格式处理后的数据

  • 【request.data】中的数据可能为【querydict】或【dict】对象

  • 代码预览

image-20240415173532313

【2.1】APIView源码分析
  • 视图类调用时,就是执行【as_view()】方法
  • 【as_view()】就是我们查看APIView源码的入口
【2.1.1】DRF的APIView的as_view()

image-20240415194225740

【2.1.2】Django的View的as_view()

image-20240415194314096

【2.1.3】DRF的APIView的dispatch()

image-20240415194408065

【2.1.3.1】包装新的request

image-20240415194516764

  • Request类实例化对象的__init__方法

image-20240415194531177

【2.1.4】APIView的request对象
  • APIView的request对象相较于django的request对象多了一些属性
  • 常用的(以下的reuqest均为APIView的request对象)
    • request.data:获取请求体中的数据,以QueryDict形式或Dict形式返回
    • request.query_params:与django的request对象中的.GET方法一致

image-20240415194652037

  • 当获取APIView的request对象中没有的属性时,将会触发__getattr__方法

image-20240415194936756

【2.1.5】源码存疑的地方
  • 如果再调用self.__getattribute__获取属性,好像没有什么必要,肯定是会报错的,为什么要多做一个异常捕获,然后再抛出一个异常呀

image-20240415195047878

【二】序列化组件

【1】序列化与反序列化的概念

  • 序列化(Serialization):将对象转换为可传输或可存储的格式的过程。在序列化过程中,对象的属性和数据被转换为一个字节流或字符串,以便在网络上传输或保存到文件中。常见的序列化格式包括 JSON、XML、Protocol Buffers 等。序列化后的数据可以在不同的系统、编程语言或应用程序之间进行交换和共享。

  • 反序列化(Deserialization):将序列化后的数据恢复为原始对象的过程。在反序列化过程中,从序列化格式(例如 JSON 字符串)中解析出对象的属性和数据,并重新构建原始对象。反序列化的过程与序列化过程相反,它将序列化后的数据转换回原始对象,以便进行进一步的处理、操作或显示。

  • 简单来说:

    • 序列化:将对象转换为可传输的格式

    • 反序列化:从 JSON 字符串、XML 文档、字节流等中解析出对象的属性和数据。

【2】序列化类(Serializer)

【2.1】定义序列化类
# 定义序列化类需要继承drf.Serializer
from rest_framework import serializers

'''简单示例'''
class MySerializer(serializers.Serializer):
    字段名 = serializers.字段类型(字段参数)
    
'''实例'''
class SnippetSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)

    def create(self, validated_data):
        """
        根据提供的验证过的数据创建并返回一个新的`Snippet`实例。
        """
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        根据提供的验证过的数据更新和返回一个已经存在的`Snippet`实例。
        """
        instance.title = validated_data.get('title', instance.title)
        return instance
  • 序列化器类的第一部分定义了序列化/反序列化的字段。
  • create()update()方法定义了在调用serializer.save()时如何创建和修改完整的实例。
【2.2】常见字段及参数
【2.2.1】常用字段类型
字段字段构造方式
BooleanFieldBooleanField()
NullBooleanFieldNullBooleanField()
CharFieldCharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailFieldEmailField(max_length=None, min_length=None, allow_blank=False)
RegexFieldRegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugFieldSlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLFieldURLField(max_length=200, min_length=None, allow_blank=False)
UUIDFieldUUIDField(format=’hex_verbose’) format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressFieldIPAddressField(protocol=’both’, unpack_ipv4=False, **options)
IntegerFieldIntegerField(max_value=None, min_value=None)
FloatFieldFloatField(max_value=None, min_value=None)
DecimalFieldDecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeFieldDateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateFieldDateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeFieldTimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationFieldDurationField()
ChoiceFieldChoiceField(choices) choices与Django的用法相同
MultipleChoiceFieldMultipleChoiceField(choices)
FileFieldFileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageFieldImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListFieldListField(child=, min_length=None, max_length=None)
DictFieldDictField(child=)
【2.2.2】选项参数
参数名称作用
max_length最大长度
min_lenght最小长度
allow_blank是否允许为空
trim_whitespace是否截断空白字符
max_value最小值
min_value最大值
【2.2.3】通用参数
参数名称说明
read_only表明该字段仅用于序列化输出,默认False
write_only表明该字段仅用于反序列化输入,默认False
required表明该字段在反序列化时必须输入,默认True
default反序列化时使用的默认值
allow_null表明该字段是否允许传入None,默认False
validators该字段使用的验证器
error_messages包含错误编号与错误信息的字典
label用于HTML展示API页面时,显示的字段名称
help_text用于HTML展示API页面时,显示的字段帮助提示信息

【3】序列化类的基本操作

【3.1】序列化
# 导入构建好的序列化类
from xx import Serializer
# 创建序列化类对象
ser = Serializer(instance=obj对象,data=request.data,...)
# 获取序列化后的数据  # 以json格式返回
ser.data
【3.1.1】序列化对象的常用参数
  1. instance:要序列化的模型实例。如果需要对现有对象进行序列化,则传递该实例。
  2. data:要反序列化的数据。如果需要从数据中创建对象,则传递该数据。通常用于创建或更新对象。
  3. context:上下文数据,可以在序列化器的各个方法中使用。通常用于在序列化器之间传递额外的信息。
  4. many:指定是否序列化多个对象。默认为 False。如果设置为 True,则可以序列化多个对象的查询集。
  5. partial:指定是否部分更新对象。默认为 False。如果设置为 True,则可以部分更新对象而不需要提供所有字段的值。
【3.2】反序列化校验
  • 序列化器在反序列化时通常会执行一系列验证操作,以确保输入的数据符合预期的格式和约束。
  • 这些验证功能可以帮助确保用户提供的数据是有效的,并且可以在存储到数据库之前进行预处理。
【3.2.1】校验级别
【3.2.1.1】字段级别的验证
class BookSerializer(serializers.Serializer):
    name = serializers.CharField(min_length=5, max_length=32, error_messages={
        'min_length': '最少不得少于5个字符',
        'max_length': '最多不得多于32个字符'
    })
    price = serializers.IntegerField(min_value=10, max_value=999, error_messages={
        'min_value': '最少不得少于10元',
        'max_value': '最多不得多于999元'
    })
    publish = serializers.CharField(min_length=3, max_length=255, error_messages={
        'min_length': '最少不得少于3个字符',
        'max_length': '最多不得多于255个字符'
    })
【3.2.1.2】自定制校验器validators
  • 与forms组件一样,可以指定validators参数自定制验证器
def func(value):
    '''验证数据格式'''
    if xxx:
        # 指定条件
        # 抛出异常
        raise ValidationError("错误信息")
    return value

class MySerializer(serializers.Serializer):
    # 可以指定多个验证器
    name = serializers.CharField(max_length=32,validators=[func,func2...])
【3.2.1.3】钩子函数
  • 局部钩子:validate_字段(self,字段)
  • 全局钩子:validate(self,attrs)
  • 校验失败 抛出指定异常ValidationError
    • from rest_framework.exceptions import ValidationError
# 局部钩子
def validate_task_name(self, name: str):
    if 'sb' in name:
        # 抛出指定异常
        raise ValidationError('不得包含侮辱性词汇')
    # 注意需要返回该字段
    return name

# 全局钩子
def validate(self, attrs):
    if attrs.get('name') == attrs.get('publish'):
        raise ValidationError('书名不得与出版社名一致')
    # 需要返回字段
    return attrs
【3.2.2】校验完成的数据 校验失败的错误信息
  • ser.is_valid():返回布尔值,True表示所有数据验证通过,False表示有错误数据

    • 通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应
  • ser.data:包含了序列化后字段及其对应数值的字典,可以直接用于生成 JSON 或其他格式的响应数据

  • ser.errors:校验失败的错误提示信息,由error_message参数指定或使用默认

# views.py
'''不需要携带参数的视图类'''
class BookViewCR(APIView):
    def get(self, request):
        book_all = Book.objects.all()
        # 将需要序列化的数据给 【instance】参数  # 如果是多条 需要传递 【many】参数
        ser = BookSerializer(instance=book_all, many=True)
        # 返回 一个数组【[{},{}]】  # 指定了many参数将视为多条数据 并按照restful规范返回数组格式
        return Response({'code': 100,'msg': 'get','results': ser.data})

    def post(self, request):
        data = request.data
        # 新增数据  # 直接将数据传入data参数中
        ser = BookSerializer(data=data)
        if ser.is_valid():
            # 校验数据
            # 校验通过  # 执行保存方法
            ser.save()
            return Response({'code': 100, 'msg': '添加成功', 'result': ser.data})
        else:
            # 校验失败
            # 返回错误信息
            return Response({'code': 101, 'msg': ser.errors})
      
'''需要携带 pk 参数 的视图类'''
class BookViewRUD(APIView):
    # 查询指定pk数据
    def get(self, request, tid):
        # 获取对象
        book = Book.objects.filter(pk=tid).first()
        if not book:
            return Response({'code': 101, 'msg': '当前书籍不存在'})
        # 将查询到的对象传入instance
        ser = BookSerializer(instance=book)
        # 返回序列化后的数据
        return Response({'code': 100, 'msg': f'查询指定【{tid}】成功', 'result': ser.data})
    
    # 修改指定数据
    def put(self, request, tid):
         # 获取对象
        book = Book.objects.filter(pk=tid).first()
        if not book:
            return Response({'code': 101, 'msg': '当前书籍不存在'})
        # 将对象传入instance  # 将需要更新的数据传入data
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            # 进行数据校验
            # 数据校验通过调用save方法保存
            ser.save()
            return Response({'code': 100, 'msg': f'修改指定【{tid}】成功', 'result': ser.data})
        else:
            # 校验失败返回错误信息
            return Response({'code': 101, 'msg': ser.errors, })
【3.2】反序列化保存 create update
  • 序列化器判断是新建对象还是更新对象的标准就是,是否传递了instance参数,数据将由data参数接受
class xxx(serializers.Serializer):
    # ... 
    def create(self, validated_data):
        '''可以对校验过的数据进行再次处理'''
        # 新增数据
        book = Book.objects.create(**validated_data)
        '''
        title = validated_data.pop('title')
        title += '爆款'
        # 为标题加上爆款二字
        Book.objects.create(**validated_data,title=title)
        '''
        return book

    def update(self, instance, validated_data):
        # 由于instance是一个对象,没办法直接使用 【queryset.update(**kwargs)】方法
        # 所以需要使用反射的方法为对象更新属性
        for key in validated_data.keys():
            setattr(instance, key, validated_data.get(key))
        instance.save()
        # 将对象返回
        return instance
【3.2.1】save(**kwargs)
  • 对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()update()中的validated_data参数获取到
# views.py
class MyView(APIView):
    def post(self,request):
        ser = Ser(data=reuqest.data)
        ser.is_valid(raise_exception=True)
        ser.save(other='xxx')
        
###############################################
# serializer.py
class Ser(serializer.Serializer):
    ...
    def create(self,validated_data):
        other = validated_data.pop('other')
        ...

【4】source参数

  • source 参数用于指定要序列化的字段的源。通常,它用于在序列化器中访问模型实例的属性或方法,并将其值包含在序列化后的数据中。
  • 当你需要访问模型实例的属性或方法,并将其值序列化到响应中时,可以使用 source 参数来指定该属性或方法的名称。这个参数告诉序列化器从哪里获取数据以进行序列化。
【4.1】source参数跨表查询
# models.py
class Books(models.Model):
    name = models.CharField(max_length=64)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 如果是外键字段  # 不使用source参数指定将会返回整个publish模型实例
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)

###############################################

# serializer.py
class Ser(serializers.Serializer):
    ...
    '''可以指定返回外键字段对象所对应的属性值'''
    publish_name = serializers.CharField(source='publish.name')
    publish_addr = serializers.CharField(source='publish.addr')
    
    '''更改字段序列化时显示的名称'''
    book_name = serializers.CharField(source='title')  # book_name的值就是模型表中的title字段
【4.2】source参数指定执行模型表中的方法
'''指定执行模型表中的方法'''
# models.py
class Task(models.Model):
    name = models.CharField(max_length=32)
    desc = models.CharField(max_length=32)

    def name2desc(self):
        '''执行一些代码'''
        return self.name + self.desc
    
############################################
# ser.py
class TaskSer(serializers.Serializer):
    # 通过source参数指定模型表中方法  # 传对应的函数名即可
    name_desc = serializers.CharField(source='name2desc')
【4.3】source参数指定显示模型表中字段名称
# models.py
class Task(models.Model):
    name = models.CharField(max_length=32)
    desc = models.CharField(max_length=32)

############################################
# ser.py
class TaskSer(serializers.Serializer):
    # task_name将作为序列化返回给前端的json数据中展示name字段的键
    task_name = serializers.CharField(source='name')
【4.4】总结
# ser.py

from rest_framework import serializers

class TaskSer(serializers.Serializer):
    # 模型表中有的字段将会一一对应
    name = serializers.CharField()
    # 可以使用source参数自定义显示给前端的json数据中的键
    task_name = serializers.CharField(source='name')
    # 模型表中的方法也可以使用同名的字段名进行调用
    name2desc = serializers.CharField()
    # 也可以使用source参数执行模型表中的方法
    name_desc = serializers.CharField(source='name2desc')
    # 直接使用外键字段将回返回当前模型表对象对应的外键对象
    user = serializers.CharField()
    # 可以使用source参数进行跨表查询
    user_name = serializers.CharField(source='user.username')
    
    
###############################################
# models.py
class Task(models.Model):
    name = models.CharField(max_length=32)
    desc = models.CharField(max_length=32)
    user = models.ForeignKey(to='User', on_delete=models.CASCADE, default=1)

    def name2desc(self):
        '''执行一些代码'''
        return self.name + self.desc


class User(models.Model):
    username = models.CharField(max_length=32, default='aaa')

image-20240422153057758

【5】使用 SerializerMethodField 定制字段

# 基本语法
字段 = serializers.SerializerMethodField()
    def get_字段(self,obj):
        '''此处的obj就是当前正在序列化的模型表对象'''
        return ...
class TaskSer(serializers.Serializer):
    # 模型表中有的字段将会一一对应
    name = serializers.CharField()
    desc = serializers.CharField()
    # 可以使用source参数进行跨表查询
    user_name = serializers.CharField(source='user.username')
    xxx = serializers.SerializerMethodField()

    def get_xxx(self, obj):
        '''
        此处的self为序列化类的对象,应当返回模型对象中的数据
        :param obj: 当前模型表对象
        :return: 想要展示的值
        '''
        return obj.desc + '这是描述哟'

image-20240422155215255

【6】使用 子序列化 定制字段

  • 使用子序列化以实现序列化类的复用
class UserSer(serializers.Serializer):
    '''user表的序列化类'''
    username = serializers.CharField()


class TaskSer(serializers.Serializer):
    # 模型表中有的字段将会一一对应
    name = serializers.CharField()
    desc = serializers.CharField()
    # 使用子序列化以实现序列化类的复用
    # 如果字段名与模型表中的外键字段一致  # 当调用子序列化时,将会自动将该外键对象传入子序列化类中
    user = UserSer()
    # 可以使用source参数指定该字段对应的外键字段  # 那么子序列化类将会自动识别外键对象
    user_obj = UserSer(source='user')

image-20240422160909664

  • 如果既不使用与外键字段同名,且不使用source参数指定,将会报错

【7】ListField和DictField

  • ListField 用于序列化和反序列化列表类型的数据。
    • 当你序列化数据时,ListField 会将列表中的每个元素序列化为相应的格式,例如 JSON 数组
    • 当你反序列化时,ListField字段将可以接受数组类型的数据
  • DictField 用于序列化和反序列化字典类型的数据。
    • 当你序列化数据时,DictField 会将字典中的键值对序列化为相应的格式,例如 JSON 对象。
    • 当你反序列化时,DictField字段将可以接受字典类型的数据
【7.1】序列化使用场景
  • 在模型表中,定义某些方法,返回列表或字典格式
  • 【注】对于多对多字段,不能直接使用ListField来进行序列化,可以使用
    • SerializerMethodField定义方法
    • 在模型表中定义方法返回列表
    • 使用子序列化并传递many=True
# models.py
class Task(models.Model):
    name = models.CharField(max_length=32)
    desc = models.CharField(max_length=32)
    user = models.ForeignKey(to='User', on_delete=models.CASCADE, default=1)

    def num_list(self):
        return [1, 2, 3]

    def info_dic(self):
        return {'id': 1, 'username': self.user.username}
##################################################

# ser.py
class TaskSer(serializers.Serializer):
    # 模型表中有的字段将会一一对应
    name = serializers.CharField()
    desc = serializers.CharField()
    # 所有的模型表中的字段类型都可以使用CharField强转  # 但是此时该字段就只是字符串了
    l_str = serializers.CharField(source='num_list')
    # 使用source参数指定
    l = serializers.ListField(source='num_list')
    # 使用同名的字段
    num_list = serializers.ListField()

    info_dic = serializers.DictField()
    dic = serializers.DictField(source='info_dic')

image-20240422162856445

  • 多对多外键字段,序列化演示
class TaskSer(serializers.Serializer):
    # 模型表中有的字段将会一一对应
    name = serializers.CharField()
    desc = serializers.CharField()

    # # 多对多外键字段
    # user = serializers.ListField()  # 将会报错
    # 使用 SerializerMethodField
    user_list = serializers.SerializerMethodField()

    def get_user_list(self, obj):
        return [user.username for user in obj.user.all()]

    # 使用子序列化
    user_list2 = UserSer(source='user', many=True)
【7.2】反序列化使用场景
  • 常用于多对多字段
# models.py
class Task(models.Model):
    name = models.CharField(max_length=32)
    desc = models.CharField(max_length=32)
    user = models.ManyToManyField(to='User')


class User(models.Model):
    username = models.CharField(max_length=32, default='aaa')
    
#################################################

# ser.py
class TaskSer(serializers.Serializer):
    # 模型表中有的字段将会一一对应
    name = serializers.CharField()
    desc = serializers.CharField()

    # 使用ListField接收列表数据  # write_only表示该字段只进行反序列化  # 只用来接收前端的数据并保存
    user = serializers.ListField(write_only=True)
    # user = serializers.CharField(write_only=True)  # "Not a valid string."  # 将会报错

    # 使用DictField接收字典形式数据
    task_info = serializers.DictField(write_only=True)
    
    
    
    def create(self, validated_data):
        # 使用post创建对象时,必须重写create方法
        # 否则会报错
        print(validated_data)
        # {'name': 'task3', 'desc': 'task3-desc', 'user': [1, 2], 'task_info': {'time': 'xxxx', 'style': 'aaaa'}}
        return validated_data  # 正常需要返回创建号的对象  # 此处将会返回序列化类序列化的数据
    
#################################################    
# views.py
class TaskView(APIView):
    def get(self, request):
        ser = TaskSer(Task.objects.all(), many=True)
        return Response(ser.data)

    def post(self, request):
        ser = TaskSer(data=request.data)
        # 反序列化校验
        ser.is_valid(raise_exception=True)
        # 调用create方法
        ser.save()
        return Response(ser.data if ser.is_valid() else ser.errors)

image-20240422165811807

【8】read_onlywrite_only

  • 当我们希望某些字段只执行序列化,也就是返回给前端时,可以使用read_only
  • 当我们希望某些字段只执行反序列化,也就是要求前端传值交由我们保存,可以使用write_only
  • 默认不填代表着,该字段既做序列化又做反序列化
class TaskSer(serializers.Serializer):
    # 模型表中有的字段将会一一对应
    name = serializers.CharField()
    desc = serializers.CharField()

    # 只做序列化,将用户信息展示给前端
    user = UserSer(many=True, read_only=True)

    # 只做反序列化,需要用户传值
    user_l = serializers.ListField(write_only=True)
    task_info = serializers.DictField(write_only=True)

image-20240422170618201

image-20240422170624778

【补充】其他知识

【1】字段参数validators
  • 在字段中添加validators选项参数,可以补充验证行为,如
def about_django(value):
    if 'django' not in value.lower():
        raise serializers.ValidationError("图书不是关于Django的")

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    title = serializers.CharField(label='名称', max_length=20, validators=[about_django])
    pub_date = serializers.DateField(label='发布日期', required=False)
    read = serializers.IntegerField(label='阅读量', required=False)
    comment = serializers.IntegerField(label='评论量', required=False)
    image = serializers.ImageField(label='图片', required=False)
【2】反序列化校验的三层校验
  1. 执行字段内部的校验
    • max_length / min_length 等
    • validators :是一个列表,可以传多个校验函数,将会依次执行列表中的所有校验函数
  2. 执行局部钩子:validate_字段
  3. 执行全局钩子:validate
【3】无法直接使用source参数反向查询
  • 直接使用 source 参数是无法实现复杂的反向查询的。source 参数通常用于简单的字段访问,例如直接从模型实例的属性中获取数据。
  • 如果需要进行复杂的反向查询,例如从关联模型中获取相关对象列表,需要使用 SerializerMethodField 并定义一个方法来实现

【9】模型类序列化类(ModelSerializer)

  • DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
  • ModelSerializer与常规的Serializer相同,但提供了:
    • 基于模型类自动生成一系列字段
    • 基于模型类自动为Serializer生成validators,比如unique_together
    • 包含默认的create()和update()的实现
from rest_framework.serializers import ModelSerializer

class XXX(ModelSerializer):
     # 不在模型表中的字段
    字段 = serializers.CharField()
    class Meta:
        # 如果是模型表中的字段  # 可以在Meta中的fields参数中指定即可
        model=对应的表
        # 模型表中的字段将于序列化类的字段类型一一对应
        fields = 需要使用的字段
        #### 【注】此处的fields需要注意,不仅仅要填写在模型表中的字段,还需要填写额外的字段 ####
        extra_kwargs = {
            '字段':{'额外添加的参数'}
        }
   
  • 【注】fields是所有使用到的字段
from .models import Task


class TaskSerV2(serializers.ModelSerializer):
    # 只做反序列化,需要用户传值
    user_l = serializers.ListField(write_only=True)
    task_info = serializers.DictField(write_only=True)
    aaa = serializers.CharField(source='name')

    class Meta:
        model = Task
        fields = '__all__'  # __all__ 表示模型表中的所有字段
        # fields = ['id','name','aaa','desc']  # 相当于
        extra_kwargs = {
            'name': {'max_length': 10}
        }
        
    '''如果所需字段就是表中需要的,就不需要重写create方法了'''
    def create(self, validated_data):
        # 由于Task表中并不需要下面两个字段,所以去除掉
        validated_data.pop('user_l')
        validated_data.pop('task_info')
        # 调用ModelSerializer中的create方法
        task = super().create(validated_data)
        return task

【三】请求与响应

【1】请求

【1.1】Request对象
def __init__(self, request, parsers=None, authenticators=None,
             negotiator=None, parser_context=None)

关键字参数:
    - request(HttpRequest). 原始请求实例。
    - parsers(list/tuple). 用于解析请求内容的解析器。
    - authenticators(list/tuple). 用于尝试验证请求用户身份的验证器。
    - negotiator(None). 协商者,用于内容协商。
    - parser_context(None). 解析器上下文,用于解析器的上下文信息。
【1.1.1】常用属性
  • .data

    • request.data 返回解析之后的请求体数据。类似于Django中标准的request.POSTrequest.FILES属性,但提供如下特性:

      • 包含了解析之后的文件和非文件数据

      • 包含了对POST、PUT、PATCH请求方式解析后的数据

      • 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据

  • .query_params

    • request.query_params与Django标准的request.GET相同,只是更换了更符合restful规范的名称,搜索参数
【1.2】Parser解析器
  • REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中
  • Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。
  • 无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
【1.2.1】三种解析器模块
模块描述请求编码格式
JSONParser用于解析 JSON 请求内容。request.data 将被填充为一个数据字典。application/json
FormParser用于解析 HTML 表单内容。request.data 将被填充为一个数据 QueryDict。通常与 MultiPartParser 一起使用以完全支持 HTML 表单数据。application/x-www-form-urlencoded
MultiPartParser用于解析多部分 HTML 表单内容,支持文件上传。request.datarequest.FILES 将分别被填充为一个 QueryDict 和 MultiValueDict。通常与 FormParser 一起使用以完全支持 HTML 表单数据。multipart/form-data
【1.2.2】默认配置
  • 默认配置中,三种解析器均被配置,所以当我们使用任意一种编码格式均可以被解析为request.data

image-20240422203118774

【1.2.3】局部使用
  • 当我们想要指定某个视图的请求只可以使用某种编码格式传输,就可以指定
# 导入模块
from rest_framework.parsers import JSONParser, FormParser


class TaskView(APIView):
    # 当我们指定使用的解析器  # 请求将只能正确的解析出json和urlencoded编码格式的请求
    parser_classes = [JSONParser, FormParser]

    def get(self, request):
        ser = TaskSer(Task.objects.all(), many=True)
        return Response(ser.data)

image-20240422204006015

【1.2.4】全局使用
# settings.py

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
    ]
}

【2】响应

【2.1】Response对象
def __init__(self, data=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None):

参数:
    - data:要返回的数据。默认为 None- status:响应状态码。默认为 None- template_name:模板名称,已弃用。改用 data 参数。默认为 None- headers:响应头信息。默认为 None- exception:是否为异常响应。默认为 False- content_type:响应内容类型。默认为 None
【2.1.1】常用属性
  • .data
    • 传给response对象的序列化后,但尚未render处理的数据
  • .status_code
    • 状态码的数字
  • .content
    • 经过render处理后的响应数据
【2.2】Renderer 渲染器
  • REST framework提供了Renderer 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。
  • 如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式
【2.2.1】两种渲染器模块
模块描述
JSONOpenAPIRenderer用于将 API 数据渲染为 OpenAPI(前身为 Swagger)规范的 JSON 格式
BrowsableAPIRenderer用于将 API 数据渲染为可浏览的 HTML 页面。它为 API 提供了一个交互式的界面,用户可以在浏览器中直观地浏览和测试 API
【2.2.2】默认配置
  • 默认配置中,两种渲染器都被配置了,所以我们可以在浏览器和postman中看到不同的界面

  • 【注】当注册了rest_framework后,前端界面将会被美化

  • 当只设置json渲染器进行渲染时,drf将使用 JSON 渲染器来渲染所有 API 响应,而不会使用任何模板来生成 HTML 页面。因此,在浏览器上就不会显示页面,而是直接显示 JSON 格式的数据。

image-20240422204408418

image-20240422205318321

【2.2.3】局部使用
  • 当我们想要指定某个视图的响应只使用JsonRender渲染
from rest_framework.renderers import JSONRenderer


class TaskView(APIView):
    # 只使用JsonRender渲染响应数据
    renderer_classes = [JSONRenderer]

    def get(self, request):
        ser = TaskSer(Task.objects.all(), many=True)
        return Response(ser.data)

image-20240422205555244

【2.2.4】全局使用
# settings.py
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ]
}
【2.3】响应状态码
  • 为了方便设置状态码,REST framewrok在rest_framework.status模块中提供了常用状态码常量。
【2.3.1】信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
【2.3.2】成功 - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
【2.3.3】重定向 - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
【2.3.4】客户端错误 - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
【2.3.5】服务器错误 - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

【四】视图组件

微信图片_20240422210120

图源:drf(详细)_51CTO博客_什么是drf

【1】两个视图基类

【1.1】APIView
  • 请在【View】中查看详细
【1.2】GenericAPIView
【1.2.1】常用类属性
  • 基本设置:

    • 以下属性控制着基本视图的行为。

    • queryset

      • 用于从视图返回对象的查询结果集。
      • 通常,你必须设置此属性或者重写 get_queryset() 方法。
      • 如果你重写了一个视图的方法,重要的是你应该调用 get_queryset() 方法而不是直接访问该属性,因为 queryset 将被计算一次,这些结果将为后续请求缓存起来。
    • serializer_class

      • 用于验证和反序列化输入以及用于序列化输出的Serializer类。
      • 通常,你必须设置此属性或者重写get_serializer_class() 方法。
    • lookup_field

      • 用于执行各个model实例的对象查找的model字段。默认为 'pk'
      • 请注意,在使用超链接API时,如果需要使用自定义的值,你需要确保在API视图序列化类设置查找字段。
    • lookup_url_kwarg

      • 应用于对象查找的URL关键字参数。它的 URL conf 应该包括一个与这个值相对应的关键字参数。
      • 如果取消设置,默认情况下使用与 lookup_field相同的值。
  • Pagination:

    • 以下属性用于在与列表视图一起使用时控制分页。

    • pagination_class

      • 当分页列出结果时应使用的分页类。
      • 默认值与 DEFAULT_PAGINATION_CLASS 设置的值相同,即 'rest_framework.pagination.PageNumberPagination'
  • Filtering:

    • filter_backends
      • 用于过滤查询集的过滤器后端类的列表。
      • 默认值与DEFAULT_FILTER_BACKENDS 设置的值相同。
【1.2.2】常用方法
  • get_queryset(self)

    • 返回列表视图中实用的查询集,该查询集还用作详细视图中的查找基础。
    • 默认返回由 queryset 属性指定的查询集。
    • 这个方法应该总是被调用而不是直接访问 self.queryset ,因为 self.queryset 只会被计算一起,然后这些结果将为后续的请求缓存起来。
    • 该方法可能会被重写以提供动态行为,比如返回基于发出请求的用户的结果集。
  • get_object(self)

    • 返回应用于详细视图的对象实例。
    • 默认使用 lookup_field 参数过滤基本的查询集。
    • 该方法可以被重写以提供更复杂的行为,例如基于多个 URL 参数的对象查找。
  • get_serializer_class(self)

    • 返回应用于序列化的类。默认为返回 serializer_class 属性的值。

    • 可以被重写以提供动态的行为,例如对于读取和写入操作使用不同的序列化器,或者为不同类型的用户提供不同的序列化器。

【1.2.3】其他方法
  • 你通常并不需要重写以下方法,虽然在你使用 GenericAPIView 编写自定义视图的时候可能会调用它们。
    • get_serializer_context(self)
      • 返回包含应该提供给序列化程序的任何额外上下文的字典。默认包含 'request', 'view''format' 这些keys。.
    • get_serializer(self, instance=None, data=None, many=False, partial=False)
      • 返回一个序列化器的实例。
    • get_paginated_response(self, data)
      • 返回分页样式的 Response 对象。
    • paginate_queryset(self, queryset)
      • 如果需要分页查询,返回页面对象,如果没有为此视图配置分页,则返回 None
    • filter_queryset(self, queryset)
      • 给定查询集,使用任何过滤器后端进行过滤,返回一个新的查询集。

【2】五个视图扩展类

  • Mixin 类提供用于提供基本视图行为的操作。
  • 注意mixin类提供动作方法,而不是直接定义处理程序方法,例如 .get().post(), 这允许更灵活的行为组成。
  • Mixin 类可以从 rest_framework.mixins导入。
视图扩展类功能方法
ListModelMixin如果查询集被填充了数据,则返回 200 OK 响应,将查询集的序列化表示作为响应的主体。相应数据可以任意分页。提供一个 .list(request, *args, **kwargs) 方法,实现列出结果集。
CreateModelMixin如果创建了一个对象,这将返回一个 201 Created 响应,将该对象的序列化表示作为响应的主体。如果序列化的表示中包含名为 url的键,则响应的 Location 头将填充该值。
如果为创建对象提供的请求数据无效,将返回 400 Bad Request,其中错误详细信息作为响应的正文。
提供 .create(request, *args, **kwargs) 方法,实现创建和保存一个新的model实例
RetrieveModelMixin如果可以检索对象,则返回 200 OK 响应,将该对象的序列化表示作为响应的主体。否则将返回 404 Not Found提供一个 .retrieve(request, *args, **kwargs) 方法,实现返回响应中现有模型的实例。
UpdateModelMixin如果一个对象被更新,这将返回一个 200 OK 响应,将对象的序列化表示作为响应的主体。
如果为更新对象提供的请求数据无效,将返回一个 400 Bad Request 响应,错误详细信息作为响应的正文。
提供 .update(request, *args, **kwargs) 方法,实现更新和保存现有模型实例。
同时还提供了一个 .partial_update(request, *args, **kwargs) 方法,这个方法和 update 方法类似,但更新的所有字段都是可选的。这允许支持 HTTP PATCH 请求。
DestroyModelMixin如果删除对象,则返回 204 No Content 响应,否则返回 404 Not Found提供一个 .destroy(request, *args, **kwargs) 方法,实现删除现有模型实例

【3】九个视图子类

  • Generic views - Django REST framework中文站点 (q1mi.github.io)
  • 这些视图子类遵循了通用的设计原则,封装了常见的 API 操作,使得开发人员能够以更高效、更简洁的方式编写 API 视图。
  • 同时,它们也提供了灵活性,允许开发人员通过继承和混合来自定义和扩展功能,以满足特定的业务需求。
  • 这些视图类可以从 rest_framework.generics导入
视图子类功能继承方法
CreateAPIView用于 仅创建 端点。GenericAPIView
CreateModelMixin
post
ListAPIView用于 只读 端点以表示模型实例集合GenericAPIView
ListModelMixin
get
RetrieveAPIView用于只读 端点以表示单个模型实例GenericAPIView
RetrieveModelMixin
get
DestroyAPIView用于只删除端点以表示单个模型实例GenericAPIView,
DestroyModelMixin
delete
UpdateAPIView用于只更新端点以表示单个模型实例GenericAPIView
UpdateModelMixin
put / patch
ListCreateAPIView用于读写端点以表示模型实例的集合GenericAPIView
ListModelMixin
CreateModelMixin
get / post
RetrieveUpdateAPIView用于 读取或更新 端点以表示 单个模型实例GenericAPIView
RetrieveModelMixin
UpdateModelMixin
get / put /patch
RetrieveDestroyAPIView用于 读取或删除 端点以表示 单个模型实例GenericAPIView
RetrieveModelMixin
DestroyModelMixin
get / delete
RetrieveUpdateDestroyAPIView用于 读写删除 端点以表示 单个模型实例GenericAPIView,
RetrieveModelMixin,
UpdateModelMixin,
DestroyModelMixin
get /put /patch /delete

【4】视图集

  • DRF允许你将一组相关视图的逻辑组合在单个类(称为 ViewSet)中。
  • 在其他框架中,你也可以找到概念上类似于 ‘Resources’ 或 'Controllers’的类似实现。
  • ViewSet 只是一种基于类的视图,它不提供任何方法处理程序(如 .get().post()),而是提供诸如 .list().create() 之类的操作。
  • ViewSet 的方法处理程序仅使用 .as_view() 方法绑定到完成视图的相应操作。
  • 通常不是在 urlconf 中的视图集中显示注册视图,而是要使用路由类注册视图集,该类会自动为你确定 urlconf。
【4.1】ViewSetMixin
  • 重写了 .as_view() 方法,使其接受一个 actions 关键字参数,用于将 HTTP 方法与资源的动作进行绑定
    • 【注】所有继承了ViewSetMixin的视图类,在路由中都需要传递actions参数
    • actions参数通常为字典形式视图类.as_view({'请求方式':'执行的方法名'})
      • 如:MyViewSet.as_view({'get': 'list', 'post': 'create'})
  • 使用时,注意继承ViewSetMixin时需要在最左侧class CommonView(ViewSetMixin,ListAPIView)
# 凡是继承了  ViewSetMixin 的视图类
# 路由写法都需要改变

######## urls.py ########
urlpatterns = [
    path('xxx/',xxx.as_view({'请求方法名':'对应的视图函数'}))
]
  • 详细原理请看【DRF源码分析】
【示例】
# urls.py

from .views import CommonView
from django.urls import path

urlpatterns = [
    path('no_router/', CommonView.as_view(actions={'get': 'xxx', 'post': 'abc'}))
]
# views.py
class CommonView(ViewSetMixin,APIView):

    def xxx(self, request):
        return Response('xxx')


    def abc(self, request):
        return Response('abc')

image-20240425154433955

【4.2】四种视图集
视图集功能继承方法
ViewSetViewSet 继承自 APIView。你可以使用任何标准属性,如 permission_classes, authentication_classes 以便控制视图集上的 API 策略。ViewSetMixin,
views.APIView
ViewSet 类不提供任何操作的实现。为了使用 ViewSet 类,你将重写该类并显式地定义动作实现。
GenericViewSetGenericViewSet 类继承自 GenericAPIView,并提供了 get_object, get_queryset 方法和其他通用视图基本行为的默认配置,但默认情况不包括任何操作。ViewSetMixin,
generics.GenericAPIView
为了使用 GenericViewSet 类,你需要覆盖该类并且要么混合所需的混合类,要么明确定义动作的实现。
ModelViewSetModelViewSet 类继承自 GenericAPIView,并通过混合各种混合类的行为来实现各种动作mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet
ModelViewSet 类提供的动作包括 .list().retrieve().create().update().partial_update() .destroy()
ReadOnlyModelViewSetReadOnlyModelViewSet 类也继承自 GenericAPIView。mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet
与 ModelViewSet 类类似,它也包括各种动作的实现,但与 ModelViewSet 不同的是,它只提供了“只读”动作,即 .list() .retrieve()

【五】路由组件

资源路由允许你快速声明给定的有足够控制器的所有公共路由。而不是为你的index…声明单独的路由,一个强大的路由能在一行代码中声明它们。

— Ruby on Rails 文档

【1】使用SimpleRouter快速生成路由

from .views import TaskViewV3
# 导入模块
from rest_framework.routers import SimpleRouter
from django.urls import path, include

# 实例化得到对象
router = SimpleRouter()
# 执行对象的register方法
router.register(prefix='task', viewset=TaskViewV3, basename='task')


urlpatterns = [
    # 获取对象的urls属性
    path('v1/', include(router.urls))
]

image-20240422224608500

【1.1】参数
  • register() 方法有两个强制参数:

    • prefix - 用于此组路由的URL前缀。

    • viewset - 处理请求的viewset类。

  • 还可以指定一个附加参数(可选):

    • base_name - 用于创建的URL名称的基本名称。
    • 如果不设置该参数,将根据视图集的queryset属性(如果有)来自动生成基本名称。
    • 注意,如果视图集不包括queryset属性,那么在注册视图集时必须设置base_name
【1.2】在路由中将快速生成的路由添加到urlpatterns的多种方式
  • 路由器实例上的.urls属性只是一个URL模式的标准列表。对于如何添加这些URL,有很多不同的写法
【1.2.1】将router.urls附加到现有视图的列表中 urlpatterns += router.urls
urlpatterns = [
    path('',根路由)
]

urlpatterns += router.urls
【1.2.2】使用Django的include函数
urlpatterns = [
    path('v1/', include(router.urls))
]

【2】SimpleRouter

  • 该路由器包括标准集合list, create, retrieve, update, partial_updatedestroy动作的路由。
  • 视图集中还可以使用@ detail_route@ list_route装饰器标记要被路由的其他方法。

image-20240422223309809

  • 默认情况下,由SimpleRouter创建的URL将附加尾部斜杠。 在实例化路由器时,可以通过将trailing_slash参数设置为`False’来修改此行为。

    • router = SimpleRouter(trailing_slash=False)
  • 路由器将匹配包含除斜杠和句点字符以外的任何字符的查找值。

  • 对于更严格(或更宽松)的查找模式,请在视图集上设置lookup_value_regex属性。

    • 例如,你可以将查找限制为有效的UUID:
class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    lookup_field = 'my_model_id'
    lookup_value_regex = '[0-9a-f]{32}'

【3】DefaultRouter

  • 这个路由器类似于上面的SimpleRouter,但是还包括一个默认返回所有列表视图的超链接的API根视图。它还生成可选的.json样式格式后缀的路由。

image-20240422225751808

  • SimpleRouter一样,在实例化路由器时,可以通过将trailing_slash参数设置为False来删除URL路由的尾部斜杠

image-20240422225856053

  • 上述是访问路由根路径时,使用DefaultRouter将会自动生成根路径的页面,如果使用SimpleRouter将会报错

【4】action装饰器

from rest_framework.decorators import action
  • @action装饰器函数是Django REST Framework中用于定义自定义动作的一种方法。
  • 它可以让你在视图集中添加额外的自定义动作,并将它们映射到特定的HTTP方法和URL路径上。
【4.1】使用场景

@action装饰器的使用场景包括但不限于以下几种情况:

  1. 自定义操作:当你需要在视图集中添加一些不属于标准CRUD操作(创建、读取、更新、删除)的自定义操作时,可以使用@action装饰器。例如,向用户发送邮件、将资源标记为喜欢或收藏等。
  2. 扩展标准操作:有时,标准的CRUD操作可能不足以满足你的需求,你可能需要为某些资源添加额外的操作。使用@action装饰器可以轻松地在视图集中添加这些自定义操作。
  3. 复杂业务逻辑:某些操作可能涉及到复杂的业务逻辑,无法简单地通过标准的CRUD操作来实现。在这种情况下,你可以使用@action装饰器来定义并实现这些操作。
  4. 对单个实例或整个集合的操作:通过detail参数,你可以指定自定义操作是针对单个实例还是整个集合的。这样可以灵活地定义不同类型的操作。
  5. 扩展API的功能:使用@action装饰器可以轻松地扩展API的功能,使其更加灵活和强大,从而满足不同场景下的需求。
【4.2】使用
  • action(methods=None, detail=None, url_path=None, url_name=None, **kwargs)

源码说明:

将一个ViewSet方法标记为可路由的动作。

@action装饰的函数将被赋予一个mapping属性,一个MethodMapper,可以用来在路由动作上添加额外的基于方法的行为。

  • 参数说明
    • methods:一个列表,表示此动作响应的HTTP方法名称。默认为仅接受GET请求。
    • detail:必填项。确定此动作是应用于实例/详情请求还是集合/列表请求。
    • url_path:定义此动作的URL片段。默认为被装饰方法的名称。
    • url_name:定义此动作的内部(reverse)URL名称。默认为被装饰方法的名称,其中下划线被连字符替换。
    • kwargs:用于在视图上设置其他属性。这可用于覆盖视图集级别的*_classes设置,类似于函数式API视图中的@renderer_classes等装饰器的工作原理
【4.3】使用案例(自动生成路由)
  • 当您使用自动生成的路由时,Django REST Framework会自动检测装饰有@action的方法,并将其转换为相应的URL路径。
  • 这是因为@action装饰器会影响ViewSet中的路由配置,并告诉框架应该将这些自定义操作公开为API端点。
# views.py
class TaskViewV3(GenericViewSet):
    queryset = Task.objects.all()
    serializer_class = TaskSer

    @action(methods=['POST'], detail=False)
    def login(self, request):
        '''登录代码逻辑'''
        return Response('xxx')

    @action(methods=['POST'], detail=False)
    def register(self, request):
        '''注册代码逻辑'''
        return Response('xxx')

    @action(methods=['PUT', 'DELETE', 'PATCH'], detail=False)
    def other(self, request, *args, **kwargs):
        '''其他请求方式的操作逻辑'''
        return Response('xxx')
# urls.py
from .views import TaskViewV3
from rest_framework.routers import SimpleRouter
from django.urls import path, include

router = SimpleRouter()
router.register(prefix='task', viewset=TaskViewV3, basename='task')
urlpatterns = [
    path('v1/', include(router.urls))
]

image-20240425152938990

image-20240425153151417

【4.3.1】使用自动生成路由 + action的url_path参数 实现自定义路径
# views.py
class CommonView(ViewSet):

    @action(methods=['get'], detail=False, url_path='xxx', url_name='xxx')
    def xxx(self, request):
        return Response('xxx')

    @action(methods=['post'], detail=False, url_path='abc', url_name='abc')
    def abc(self, request):
        return Response('abc')
# urls.py
router = SimpleRouter()
router.register(prefix='router', viewset=CommonView, basename='common')
urlpatterns = [
	# 此处留空
]
urlpatterns += router.urls

image-20240425160914787

【4.4】使用案例2(不使用自动生成路由的情况下使用aciton装饰器)
  • @action 装饰器的作用在于为自动生成路由的情况下提供便利。但即使在手动定义路由的情况下,@action 装饰器仍然有几个作用:
    1. 提供附加的元数据: 使用 @action 装饰器可以为自定义操作提供附加的元数据,例如 detail 参数用于指定操作是针对单个对象还是整个集合的。
    2. 提高可读性: 在视图类中使用 @action 装饰器标记自定义操作,可以使代码更具可读性和清晰度,因为它明确指示了这是一个自定义操作。
    3. 集中定义自定义操作: 使用 @action 装饰器将自定义操作直接与视图类关联,使得在代码中更容易找到和理解视图类的功能。
# urls.py
from .views import CommonView
from django.urls import path

urlpatterns = [
    path('no_router/', CommonView.as_view(actions={'get': 'xxx', 'post': 'abc'}))
]
class CommonView(ViewSet):

    @action(methods=['get'], detail=False)
    def xxx(self, request):
        return Response('xxx')

    @action(methods=['post'], detail=False)
    def abc(self, request):
        return Response('abc')

自动生成路由很方便,建议使用自动生成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值