Skip to content

RESTful

web应用模式

1.前后端不分离

img

在**前后端不分离**的应用模式中,前端页面**看到的效果都是**由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的**耦合度很高**。

这种应用模式**比较适合纯网页**应用,但是当后端对接App时,App可能并不需要后端返回一个HTML网页,而仅仅是数据本身,所以后端原本返回网页的接口不再适用于前端App应用,为了对接App后端还需再开发一套接口。

2.前后端分离

img

在前后端分离的应用模式中,后端仅返回前端所需的数据,不再渲染HTML页面,不再控制前端的效果。至于前端用户看到什么效果,从后端请求的数据如何加载到前端中,都由前端自己决定,网页有网页的处理方式,App有App的处理方式,但无论哪种前端,所需的数据基本相同,后端仅需开发一套逻辑对外提供数据即可。

在前后端分离的应用模式中 ,前端与后端的耦合度相对较低。我们通常将后端开发的每个视图都称为一个**接口**,或者**API**,前端通过访问接口来对数据进行增删改查。

认识RESTful

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。

非REST的url:http://.../queryGoods?id=1001&type=t01

REST的url:http://.../t01/goods/1001

REST特点:url简洁,将参数通过url传到服务器

RESTful设计思想

请求

1.域名

应该尽量将API部署在专用域名之下。

2.版本

3.路径

4.HTTP动词

5.过滤信息

响应

1.状态码

2.错误处理

3.返回结果

4.返回的格式

Django****开发****REST 接口

gitee.com

  • 将请求的数据(如JSON格式)转换为模型类对象**(反序列化)**
  • 操作数据库
  • 将模型类对象转换为响应的数据(如JSON格式)(序列化

明确****REST****接口开发的核心任务

序列化:****Django中的模型对象转换为JSON字符串

反序列化:****JSON字符串转换为Django中的模型类对象

1.在开发REST API接口时,我们在**视图**中需要做的最核心的事是:

  • 将前端发送的数据反序列化为模型类对象,并保存到数据库中。
  • 将数据库数据序列化为前端所需要的格式,并返回;

Django REST framework 简介

开发REST API

  • :校验请求数据 -> 执行反序列化过程 ->保存数据库 ->将保存的对象序列化并返回
  • :判断要删除的数据是否存在 -> 执行数据库删除
  • :判断要修改的数据是否存在 ->校验请求的数据 -> 执行反序列化过程 ->保存数据库 ->将保存的对象序列化并返回
  • :查询数据库 -> 将数据序列化并返回

特点

  • 提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
  • 提供了丰富的类视图、Mixin扩展类,简化视图的编写;
  • 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
  • 多种身份认证和权限认证方式的支持;
  • 内置了限流系统;
  • 直观的 API web 界面;
  • 可扩展性,插件丰富

使用步骤

1.安装
pip install djangorestframework

2.注册子应用
INSTALLED_APPS = [
    ...
    'rest_framework',
]

为什么要用DRF

Django中用JsonResponse开发API需要根据用户请求信息构建字典格式数据内容,这种方式开发API很容易造成代码冗余,不利于功能的变更和维护。

为了简化API的开发过程,我们可以使用Django Rest Framework框架实现API开发。使用框架开发不仅能减少代码冗余,还可以规范代码的编写格式,这对企业级开发来说很有必要,毕竟每个开发人员的编程风格存在一定的差异,开发规范化可以方便其他开发人员查看和修改。

DRF使用流程

  1. 先用定义Django原生models
  2. 序列化(serializers)
  3. 视图集(业务逻辑)
  4. 在子路由注册视图集
  5. 在总路由注册

序列化和反序列化

Serializers字段和选项

1.定义Serializer类

from rest_framework import serializers

Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。

**serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。**serializer是独立于数据库之外的存在。

2.字段与选项

字段 字段构造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(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"
IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices与Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

通用参数:

参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认False
default 反序列化时使用的默认值
label 用于HTML展示API页面时,显示的字段名称

选项参数:

参数名称 作用
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
max_value 最大值
min_value 最小值

3.创建Serializer对象

# Serializer的构造方法为
Serializer(instance=None,data=empty,**kwarg)

# 1.用于序列化时,将模型类对象传入instance参数
serializer = BookInfoSerializer(instance=book)
#或者
serializer = BookInfoSerializer(book)

# 2.用于反序列化时,将要被反序列化的数据传入data参数
serializer = BookInfoSerializer(data={'name':'xxxx','pub_date':'2000-01-10'})

序列化(响应、后端返回JSON给前端)

基本使用

# 1.先查出一个图书对象
from learning.books.models import BookInfo
book = BookInfo.objects.get(id=4)

# 2.构造序列化器对象
from learning.books.serializer import BookInfoSerializer
serializer = BookInfoSerializer(book)  # 传递模型实例

# 3.获取序列化数据(对象转换为字典的数据)
serializer.data
{'id': 4, 'name': '雪山飞狐', 'pub_date': '1987-11-11', 'readcount': 58, 'commentcount': 24}

# 4.如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明
b = BookInfo.objects.all()
s = BookInfoSerializer(b,many=True)  # 如果模型返回列表,设置many=True
s.data
[{'id': 1, 'name': '射雕英雄传put修改', 'pub_date': '1980-05-01', 'readcount': 12, 'commentcount': 34}, {'id': 2, 'name': '天龙八部', 'pub_date': '1986-07-24', 'readcount': 36, 'commentcount': 40}, {'id': 3, 'name': '笑傲江湖', 'pub_date': '1995-12-24', 'readcount': 20, 'commentcount': 80}, {'id': 4, 'name': '雪山飞狐', 'pub_date': '1987-11-11', 'readcount': 58, 'commentcount': 24}]

关联对象嵌套序列化

1.IntegerField

class PeopleInfoSerializer(serializers.Serializer):
    # 根据表字段来获取外键
    # 此字段将被序列化为关联对象的主键。
    book_id = serializers.IntegerField(label='书籍ID') 

from learning.books.models import PeopleInfo
from learning.books.serializer import PeopleInfoSerializer
person = PeopleInfo.objects.get(id=10)
serializer = PeopleInfoSerializer(person)
serializer.data
{'id': 10, 'name': '令狐冲', 'password': '123456abc', 'description': '独孤九剑', 'book_id': 3, 'is_delete': False}

2.PrimaryKeyRelatedField

class PeopleInfoSerializer(serializers.Serializer):
    # 此字段将被序列化为关联对象的主键
    # 包含read_only=True参数时,该字段将不能用作反序列化使用
    # 包含queryset参数时,将被用作反序列化时参数校验使用
    book = serializers.PrimaryKeyRelatedField(label='图书', read_only=True)
    # 或  
    # book = serializers.PrimaryKeyRelatedField(label='图书', queryset=BookInfo.objects.all())

p = PeopleInfo.objects.get(id=10)
s = PeopleInfoSerializer(instance=p)
s.data
{'id': 10, 'name': '令狐冲', 'password': '123456abc', 'description': '独孤九剑', 'book': 3}

3.StringRelatedField

此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)

class BookInfo(models.Model):
    pass
    def __str__(self):
        """定义每个数据对象的显示信息"""
        return "BookInfo" + self.name

class PeopleInfoSerializer(serializers.Serializer):
    book = serializers.StringRelatedField(label='图书')


from learning.books.models import PeopleInfo
from learning.books.serializer import PeopleInfoSerializer
p  = PeopleInfo.objects.get(id=10)
s = PeopleInfoSerializer(p)
{'id': 10, 'name': '令狐冲', 'password': '123456abc', 'description': '独孤九剑', 'book': 'BookInfo笑傲江湖'}

4.使用关联对象的序列化器

from rest_framework import serializers

class PeopleInfoSerializer(serializers.Serializer):
    pass


class BookInfoSerializer(serializers.Serializer):
    #一本书籍关联多个人物
    people=PeopleInfoSerializer(many=True)


from learning.books.models import BookInfo
from learning.books.serializer import BookInfoSerializer
b = BookInfo.objects.get(id=1)
s = BookInfoSerializer(b)
s.data
{'id': 1, 'name': '射雕英雄传put修改', 'pub_date': '1980-05-01', 'readcount': 12, 'commentcount': 34, 'people': [{'id': 1, 'name': '郭靖', 'password': '123456abc', 'description': '降龙十八掌'}, {'id': 2, 'name': '黄蓉', 'password': '123456abc', 'description': '打狗棍法'}, {'id': 3, 'name': '黄药师', 'password': '123456abc', 'description': '弹指神通'}, {'id': 4, 'name': '欧阳锋', 'password': '123456abc', 'description': '蛤蟆功'}, {'id': 5, 'name': '梅超风', 'password': '123456abc', 'description': '九阴白骨爪'}]}

反序列化(请求--前端传给后端的)

1.验证

使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

在获取反序列化的数据前,必须调用**is_valid()**方法进行验证,验证成功返回True,否则返回False。

验证失败,可以通过序列化器对象的**errors**属性获取错误信息,返回字典,包含了字段和字段的错误。

验证成功,可以通过序列化器对象的**validated_data**属性获取数据。

# 在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label='ID')
    name = serializers.CharField(label='名称')
    pub_date = serializers.DateField(label='发布日期')
    readcount = serializers.IntegerField(label='阅读量')
    commentcount = serializers.IntegerField(label='评论量')


# 验证is_valid() 为False
from learning.books.serializer import BookInfoSerializer

data = {
     'name':'Python高级',
     'pub_date':'2020-1-1',
     'readcount':100,
     'commentcount':200}

serializer = BookInfoSerializer(data=data)
serializer.is_valid()
False
serializer.errors
{'id': [ErrorDetail(string='该字段是必填项。', code='required')]}



# 验证is_valid() 为True
from learning.books.serializer import BookInfoSerializer
data = {
     'id':100,
     'name':'Python高级',
     'pub_date':'2020-1-1',
     'readcount':100,
     'commentcount':200}
 serializer = BookInfoSerializer(data=data)
 serializer.is_valid()
True
serializer.errors
{}

1.字段类型

is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError可以通过传递raise_exception=True参数开启REST framework接收到此异常会向前端返回HTTP 400 Bad Request响应

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label='ID')
    name = serializers.CharField(label='名称')
    pub_date = serializers.DateField(label='发布日期')
    readcount = serializers.IntegerField(label='阅读量')
    commentcount = serializers.IntegerField(label='评论量')



# 失败时抛出异常
from learning.books.serializer import BookInfoSerializer
data = {
     'id':100,
     'name':'Python高级',
     'pub_date':'2020',
     'readcount':100,
     'commentcount':200}

s = BookInfoSerializer(data=data)
s.is_valid(raise_exception=True)
False
s.errors
{'pub_date': [ErrorDetail(string='日期格式错误。请从这些格式中选择:YYYY-MM-DD。', code='invalid')]}

2.字段选项

read_only

# 像id这样的主键值,一般我们都是让数据库自动生成,所以一般不会传入。则需要设置为 read_only
id = serializers.IntegerField(label='ID',read_only=True)

write_only

# 只写入。我们在进行反序列化的时候,必须要求传入该字段。在进行序列化操作的时候不会获取到该字段的值。

password = serializers.IntegerField(label='密码',read_only=True)

read_only=True

write_only=True

id = serializers.IntegerField(label='ID',read_only=True)    表明该字段仅用于序列化输出
password = serializers.IntegerField(label='ID',write_only=True)   表明该字段仅用于反序列化输入
class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label='ID')
    name = serializers.CharField(label='名称')
    pub_date = serializers.DateField(label='发布日期')
    readcount = serializers.IntegerField(label='阅读量')
    commentcount = serializers.IntegerField(label='评论量')


# 验证is_valid() 为False
from learning.books.serializer import BookInfoSerializer

data = {
     'name':'Python高级',
     'pub_date':'2020-1-1',
     'readcount':100,
     'commentcount':200}

serializer = BookInfoSerializer(data=data)
serializer.is_valid()
False
serializer.errors
{'id': [ErrorDetail(string='该字段是必填项。', code='required')]}

3.validate_fieldname(字段名)

class BookInfoSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='名称')
    pub_date = serializers.DateField(label='发布日期')
    readcount = serializers.IntegerField(label='阅读量')
    commentcount = serializers.IntegerField(label='评论量')
    # 需求数据获取书籍以及书籍关联的人物
    # 一本书籍关联多个人物
    people = PeopleInfoSerializer(many=True, read_only=True)

    def validate_readcount(self, value):
        """
        对<field_name>字段进行验证
        """
        if value < 0:
            raise serializers.ValidationError('阅读数量不能为负数')
        return value


from learning.books.serializer import BookInfoSerializer
data = {'name':'python高级','pub_date':'2021-01-01','readcount':-100,'commentcount':200}
s = BookInfoSerializer(data=data)
s.is_valid(raise_exception=True)

# 报错
Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm 2023.2.4\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcode
    coro = func()
  File "<input>", line 1, in <module>
  File "C:\Users\50599\Desktop\start\lib\site-packages\rest_framework\serializers.py", line 231, in is_valid
    raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'readcount': [ErrorDetail(string='阅读数量不能为负数', code='invalid')]}

4.validate

在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证

class BookInfoSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='名称')
    pub_date = serializers.DateField(label='发布日期')
    readcount = serializers.IntegerField(label='阅读量')
    commentcount = serializers.IntegerField(label='评论量')
    # 需求数据获取书籍以及书籍关联的人物
    # 一本书籍关联多个人物
    people = PeopleInfoSerializer(many=True, read_only=True)


    def validate(self, attrs):
        readcont = attrs['readcont']
        commentcount = attrs['commentcount']
        if commentcount > readcont:
            raise serializers.ValidationError('评论量不能大于阅读量')
        return attrs


from learning.books.serializer import BookInfoSerializer
data = {
     'name':'Python高级',
     'pub_date':'2020-01-01',
     'readcount':100,
     'commentcount':200}
s = BookInfoSerializer(data=data)
s.is_valid(raise_exception=True)

Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm 2023.2.4\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcode
    coro = func()
  File "<input>", line 8, in <module>
  File "C:\Users\50599\Desktop\start\lib\site-packages\rest_framework\serializers.py", line 231, in is_valid
    raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'non_field_errors': [ErrorDetail(string='评论量不能大于阅读量', code='invalid')]}

2.保存

如果在验证成功后,想要基于validated_data完成数据对象的创建,可以通过实现create()和update()两个方法来实现。

class BookInfoSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='名称')
    pub_date = serializers.DateField(label='发布日期')
    readcount = serializers.IntegerField(label='阅读量')
    commentcount = serializers.IntegerField(label='评论量')
    # 需求数据获取书籍以及书籍关联的人物
    # 一本书籍关联多个人物
    people = PeopleInfoSerializer(many=True, read_only=True)

    # def validate_readcount(self, value):
    #     """对<field_name>字段进行验证"""
    #     if value < 0:
    #         raise serializers.ValidationError('阅读数量不能为负数')
    #     return value

    def validate(self, attrs):
        readcount = attrs['readcount']
        commentcount = attrs['commentcount']
        if commentcount > readcount:
            raise serializers.ValidationError('评论量不能大于阅读量')
        return attrs

    def create(self, validated_data):
        return BookInfo.objects.create(**validated_data)

# 验证
from learning.books.serializer import BookInfoSerializer
data = {
     'name':'Python高级',
     'pub_date':'2020-01-01',
     'readcount':1000,
     'commentcount':200}

# serializer 名字不能改
serializer = BookInfoSerializer(data=data)
serializer.is_valid()
True
serializer.save()
<BookInfo: BookInfoPython高级1>
class BookInfoSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='名称')
    pub_date = serializers.DateField(label='发布日期')
    readcount = serializers.IntegerField(label='阅读量')
    commentcount = serializers.IntegerField(label='评论量')
    # 需求数据获取书籍以及书籍关联的人物
    # 一本书籍关联多个人物
    people = PeopleInfoSerializer(many=True, read_only=True)

    def validate(self, attrs):
        readcount = attrs['readcount']
        commentcount = attrs['commentcount']
        if commentcount > readcount:
            raise serializers.ValidationError('评论量不能大于阅读量')
        return attrs

    def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.pub_date = validated_data.get('pub_date', instance.pub_date)
        instance.readcount = validated_data.get('readcount', instance.readcount)
        instance.commentcount = validated_data.get('commentcount', instance.commentcount)
        instance.save()
        return instance


# 验证
from learning.books.models import BookInfo
from learning.books.serializer import BookInfoSerializer

b = BookInfo.objects.get(id=1)
data = {
     'name':'Python高级4',
     'pub_date':'2020-01-01',
     'readcount':1000,
     'commentcount':200}
serailizer = BookInfoSerializer(instance=b,data=data,partial=True)
serailizer.is_valid(raise_exception=True)
serailizer.save()

img

模型类序列化器ModelSerializer

from learning.books.models import BookInfo
from rest_framework import serializers


class BookInfoModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 指明参照那个模型类
        fields = '__all__'  # 添加的字段 all 表示全部
        # fields = ('name', 'readcount')  # 添加部分字段
        # exclude = ('image',)  # 排除字段
        read_only_fields = ('id', 'name')  # 指明只读字段,仅用于序列化输出的字段
        # 使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
        extra_kwargs = {
            'readcount': {'min_value': 0, 'required': False},  # required 表明该字段在反序列化时必须输入默认
            'commentcount': {'max_value': 0, 'required': True},
        }

进阶使用

1.保存1个人物信息

# body1
data = {
    'book':1,
    'name': '靖哥哥',
    'password': '123456abc',
}

class PeopleInfoModelSerializer(serializers.ModelSerializer):class Meta:
        model = PeopleInfo
        fields = ['id','book','name','password']
        extra_kwargs = {
            'password': {'write_only':True}
        }

# write_only表明该字段仅用于反序列化输入。在序列化输出时忽略该字段。
# body2
data = {
    'book_id':1,
    'name': '靖哥哥',
    'password': '123456abc'
}

from rest_framework import serializers
from book.models import PeopleInfo
class PeopleInfoModelSerializer(serializers.ModelSerializer):
    book_id=serializers.IntegerField()

    class Meta:
        model = PeopleInfo
        fields = ['id','book_id','name','password']
        extra_kwargs = {
            'password': {'write_only':True}
        }

# 或者
from rest_framework import serializers
from book.models import PeopleInfo
class PeopleInfoModelSerializer(serializers.ModelSerializer):
    book_id=serializers.IntegerField(required=False)
    book=serializers.StringRelatedField()

    class Meta:
        model = PeopleInfo
        fields = ['id','book_id','book','name','password']
        extra_kwargs = {
            'password': {'write_only':True}
        }

# 外键book或者book_id都可以保存数据。主要看前端传递过来的数据形式
# body3
data = {
    'book_id':1,
    'name': '靖哥哥',
    'password': '123456abc',
    'is_delete': 1
}


from rest_framework import serializers
from book.models import PeopleInfo,BookInfo
class PeopleInfoModelSerializer(serializers.ModelSerializer):
    book_id=serializers.IntegerField(required=False)
    book=serializers.StringRelatedField()

    class Meta:
        model = PeopleInfo
        fields = ['id','book_id','book','name','password','is_delete']
        extra_kwargs = {
            'password': {'write_only':True},
            'is_delete': {'read_only':True}
        }

#  read_only表明该字段仅用于序列化输出。反序列化时忽略次字段。

# body4

data = {
    'book_id':1,
    'name': '靖哥哥',
    'password': '123456abc',
    'description': '描述',
    'is_delete': 1
}

from rest_framework import serializers
from book.models import PeopleInfo,BookInfo
class PeopleInfoModelSerializer(serializers.ModelSerializer):
    book_id=serializers.IntegerField(required=False)
    book=serializers.StringRelatedField()

    class Meta:
        model = PeopleInfo
        fields = ['id','book_id','book','name','password','is_delete']
        extra_kwargs = {
            'password': {'write_only':True},
            'is_delete': {'read_only':True}
        }

# description没有在序列化器中定义字段。如果需要验证或保存某一个字段是必须要在序列化器中定义该字段

2.保存n个人物信息

# body5
[
    {
        'book_id': 1,
        'name': '靖妹妹~~~',
        'password':'123456abc'
    },
    {
        'book_id': 1,
        'name': '靖表哥~~~',
        'password': '123456abc'
    }
]


from rest_framework import serializers
from book.models import PeopleInfo
class PeopleInfoModelSerializer(serializers.ModelSerializer):
    book_id=serializers.IntegerField(required=False)
    book=serializers.StringRelatedField()

    class Meta:
        model = PeopleInfo
        fields = ['id','book_id','book','name','password','is_delete']
        extra_kwargs = {
            'password': {'write_only':True},
            'is_delete': {'read_only':True}
        }

# 进行反序列化也可以保存字典列表,需要设置many=True

3.保存1本新书籍和n个新人物信息

Serializer relations - Django REST framework

{
    'name':'离离原上草',
    'people':[
        {
            'name': '靖妹妹111',
            'password': '123456abc'
        },
        {
            'name': '靖表哥222',
            'password': '123456abc'
        }
    ]
}

from rest_framework import serializers
from book.models import PeopleInfo,BookInfo
class PeopleInfoModelSerializer(serializers.ModelSerializer):
    book_id=serializers.IntegerField(required=False)
    book=serializers.StringRelatedField()

    class Meta:
        model = PeopleInfo
        fields = ['id','book_id','book','name','password','is_delete']
        extra_kwargs = {
            'password': {'write_only':True},
            'is_delete': {'read_only':True}
        }

class BookInfoModelSerializer(serializers.ModelSerializer):
    people=PeopleInfoModelSerializer(many=True)
    class Meta:
        model = BookInfo
        fields = '__all__'def create(self, validated_data):

        people=validated_data.pop('people')

        book=BookInfo.objects.create(**validated_data)

        for person in people:
            PeopleInfo.objects.create(book=book,**person)

        return book

# 默认情况下,嵌套串行器是只读的。如果要支持对嵌套序列化器字段的写操作,则需要创建create()或update()方法,以明确指定应如何保存数据。

视图

img

img

1.Request与Response

1.Request

from rest_framework.request import Request

# REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典对象保存到Request对象中。
# Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。

常用属性

01.data

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

  • 包含了对POST、PUT、PATCH请求方式解析后的数据
  • 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
# 源码
from rest_framework.request import Request
class Request:

  @property
  def data(self):
      if not _hasattr(self, '_full_data'):
          self._load_data_and_files()
      return self._full_data

  def _load_data_and_files(self):
      """
      Parses the request content into `self.data`.
      """
      if not _hasattr(self, '_data'):
          self._data, self._files = self._parse()
          if self._files:
              self._full_data = self._data.copy()
              self._full_data.update(self._files)
          else:
              self._full_data = self._data

          # if a form media type, copy data & files refs to the underlying
          # http request so that closable objects are handled appropriately.
          if is_form_media_type(self.content_type):
              self._request._post = self.POST
              self._request._files = self.FILES
02.query_params

request.query_params与Django标准的request.GET相同。

from rest_framework.request import Request

class Request:
    @property
    def query_params(self):
        """
        More semantically correct name for request.GET.
        """
        return self._request.GET

2.Response

REST framework提供了Renderer渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前**端请求中未进行Accept声明,则会采用默认方式处理响应数据**,我们可以通过配置来修改默认响应格式。

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}

1.构造方式

Response(data, status=None, template_name=None, headers=None, content_type=None)

"""
data只需传递python的内建类型数据即可。
data不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer序列化器序列化处理后(转为了Python字典类型)再传递给data参数。

data: 为响应准备的序列化处理后的数据;
status: 状态码,默认200;
template_name: 模板名称,如果使用HTMLRenderer时需指明;
headers: 用于存放响应头信息的字典;
content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
"""

2.状态码

1)信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
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
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
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
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

2.视图

1.APIView(一级)

Views - Django REST framework

img

from django.views.generic.base import View
from rest_framework.views import APIView

# APIView继承自Django中View

"""
APIView与View的不同之处在于:
    传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
    视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
    任何APIException异常都会被捕获到,并且处理成合适的响应信息;
    在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

支持定义的属性:
    authentication_classes列表或元祖,身份认证类
    permissoin_classes列表或元祖,权限检查类
    throttle_classes列表或元祖,流量控制类
"""


from django.views.generic.base import View
from rest_framework.views import APIView
from learning.books.models import BookInfo
from learning.books.modelserializer import BookInfoModelSerializer
from rest_framework.response import Response


class BookListApiView(APIView):
    def get(self, request):
        # 1.查询数据
        books = BookInfo.objects.all()
        # 2.创建序列化器,并传递查询结果集(如果是列表设置many=True)
        serializer = BookInfoModelSerializer(books, many=True)
        # 3.返回响应 Serializer.data
        return Response(serializer.data)  # 列表套字典

    def post(self, request):
        # 1.接受参数
        book_dict = request.data
        # 2.创建序列化器,并传递参数
        serializer = BookInfoModelSerializer(data=book_dict)
        # 3.验证数据,并根据验证结果进行判断
        if serializer.is_valid():
            # 4.验证数据没有问题,调用序列化器的save方法。来触发序列化器的create方法,create方法会调用模型来保存到数据库中
            serializer.save()
            # 5.返回响应 Serializer.data  就是字典数据
            return Response(serializer.data)
        else:
            # 数据验证有问题,返回错误信息
            msg = serializer.errors
            return Response({'msg': f'{msg}'})

img

2.GenericAPIView(二级)

img

继承自APIVIew,增加了对于**列表视图**和**详情视图**可能用到的通用支持方法。通常使用时,可搭配一个或多个Mixin扩展类。

属性

  1. 列表详情视图通用
  2. **queryset**列表视图的查询集
  3. **serializer_class**视图使用的序列化器
  4. 详情页视图使用
  5. **lookup_field**查询单一数据库对象时使用的条件字段,默认为'pk'
  6. **lookup_url_kwarg**查询单一数据时URL中的参数关键字名称,默认与**look_field**相同

方法

  1. 列表详情视图通用

get_queryset(self)

返回视图使用的查询集,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写,例如:

def get_queryset(self):
    return BookInfo.objects.all()

get_serializer_class(self)

返回序列化器类,默认返回serializer_class,可以重写,例如:

def get_serializer_class(self):
    return BookInfoModelSerializer

get_serializer(self,_args, *_kwargs)

返回序列化器对象,被其他视图或扩展类使用,如果我们在视图中想要获取序列化器对象,可以直接调用此方法。注意,在提供序列化器对象的时候,****REST framework会向对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。

  1. 详情页视图使用

get_object(self)

返回详情视图所需的模型类数据对象,默认使用lookup_field参数来过滤queryset。 在试图中可以调用该方法获取详情信息的模型类对象。

若详情访问的模型类对象不存在,会返回404。

3.MIxin

0**1.ListModelMixin**

列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。

该Mixin的list方法会对数据进行过滤和分页。

# 源码
class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

02.CreateModelMixin

创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。

如果序列化器对前端发送的数据验证失败,返回400错误。

# 源码
class CreateModelMixin:
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}

03.RetrieveModelMixin

详情视图扩展类,提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。

如果存在,返回200, 否则返回404。

# 源码
class RetrieveModelMixin:
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

04.UpdateModelMixin

更新视图扩展类,提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。

同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。

成功返回200,序列化器校验数据失败时,返回400错误。

class UpdateModelMixin:
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

05.DestroyModelMixin

删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。

成功返回204,不存在返回404。

class DestroyModelMixin:
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

demo

class BookListGenericMixinView(ListModelMixin, CreateModelMixin,
                               GenericAPIView):
    # 设置查询结果集属性
    queryset = BookInfo.objects.all()
    # 设置序列化属性
    serializer_class = BookInfoModelSerializer

    def get(self, request):
        """调用Mixin的list方法"""
        return self.list(request)

    def post(self, request):
        """调用Mixin的create方法"""
        return self.create(request)


class BookListGenericMixinViews(UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericAPIView):
    # 设置查询结果集属性
    queryset = BookInfo.objects.all()
    # 设置序列化属性
    serializer_class = BookInfoModelSerializer

    def get(self, request, pk):
        """调用Mixin的retrieve方法"""
        return self.retrieve(request)

    def put(self, request, pk):
        """调用Mixin的update的方法"""
        return self.update(request)

    def delete(self, request, pk):
        """调用Mixin的destory的方法"""
        return self.destroy(request)

img

4.子类视图(三级)

1) CreateAPIView

from rest_framework.generics import CreateAPIView
"""
提供 post 方法
继承自: GenericAPIView、CreateModelMixin 
"""

2)ListAPIView

from rest_framework.generics import ListAPIView
"""
提供 get 方法
继承自:GenericAPIView、ListModelMixin
"""

3)RetireveAPIView

 from rest_framework.generics import RetrieveAPIView
"""
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin 
"""

4)DestoryAPIView

 from rest_framework.generics import DestroyAPIView
"""
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin 
"""

5)UpdateAPIView

from rest_framework.generics import UpdateAPIView
"""
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
""" 

6)RetrieveUpdateAPIView

 from rest_framework.generics import RetrieveUpdateAPIView
"""
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
"""

7)RetrieveUpdateDestoryAPIView

from rest_framework.generics import RetrieveUpdateDestroyAPIView
"""
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
"""

3.视图集ViewSet

Viewsets - Django REST framework

视图集操作

REST 框架中包含的默认路由器将为一组标准的创建/检索/更新/销毁样式操作提供路由,如下所示:

class UserViewSet(viewsets.ViewSet):
    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.

    If you're using format suffixes, make sure to also include
    the `format=None` keyword argument for each action.
    """

    def list(self, request):
        """
        查所有
        """
        pass

    def create(self, request):
        """

        """
        pass

    def retrieve(self, request, pk=None):
        """
        查某一个
        """
        pass

    def update(self, request, pk=None):
        """
        改全部
        """
        pass

    def partial_update(self, request, pk=None):
        """
        改部分
        """
        pass

    def destroy(self, request, pk=None):
        """

        """
        pass

使用ViewSet类比使用View类有两个主要优点。

  • 重复的逻辑可以合并成一个类。例如我们只需要指定queryset一次,它将用于多个视图。
  • 通过使用路由器,我们不再需要处理自己的URL配置

1.ViewSet

一个ViewSet类只是**一种基于类的View,**继承自APIView,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

在ViewSet中,它不提供任何方法处理程序,需要我们自己重写该类并明确实现action方法。

在调度期间,以下属性在ViewSet.

  • basename用于创建的 URL 名称的基础。
  • action当前操作的名称(例如,list, create)。
  • detail布尔值,指示当前操作是否配置为列表视图或详细视图。
  • suffix视图集类型的显示后缀 - 镜像detail属性。
  • name视图集的显示名称。这个论点与 是互斥的suffix
  • description视图集的各个视图的显示描述。
from rest_framework.viewsets import ViewSet
from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from learning.books.modelserializer import BookInfoModelSerializer
from learning.books.models import BookInfo


class BookViewSet(ViewSet):
    def list(self, request):
        queryset = BookInfo.objects.all()
        serializer = BookInfoModelSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = BookInfo.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = BookInfoModelSerializer(user)
        return Response(serializer.data)

2.GenericViewSet

继承自GenericAPIView,作用也与GenericAPIVIew类似,提供了get_object、get_queryset等方法便于列表视图与详情信息视图的开发。在GenericAPIView中,没有提供任何动作action方法,需要我们自己覆盖该类并混合所需的混合类,或者明确定义操作实现action方法

img

3.ModelViewSet

继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

ModelViewSet类所继承GenericAPIView,包括用于各种动作实现方式中,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

由提供的动作ModelViewSet类是.list().retrieve().create().update().partial_update(),和.destroy()

# 因为ModelViewSet扩展GenericAPIView,我们通常需要提供至少queryset和serializer_class属性

class BookViewSet(ViewSet, ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

4.ReadOnlyModelViewSet

继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin。

ModelViewSet它一样,它还包括各种操作的实现,但不同于ModelViewSet只提供“只读”操作,list()而且retrieve()

img

4.路由Router

Routers - Django REST framework

对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由列表信息。

REST framework提供了两个router

  • SimpleRouter
  • DefaultRouter

1.使用方法

# 1.创建router对象,并注册视图集
register(prefix, viewset,basename)
# prefix 该视图集的路由前缀
# viewset 视图集
# basename路由名称的前缀

from rest_framework import routers
router = routers.DefaultRouter()
router.register('books', BookViewSet, basename='book')

# 2.添加路由数据
# 方法一
urlpatterns = [
    ...
    path('', include(router.urls))
]

# 方法二
urlpatterns = [
    ...
]
urlpatterns += router.urls

2.路由router形成URL的方式

img

img

DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。

drf-yasg

drf-yasg是一个Swagger / OpenAPI 2生成工具,无需使用 Django Rest Framework 提供的模式生成即可实现。

它的目标是尽可能多地实现OpenAPI 2规范 - 嵌套模式、命名模型、响应主体、枚举/模式/最小/最大验证器、表单参数等 - 并生成可与swagger-codegen.

这也转化为一个非常有用的交互式文档查看器,其形式为swagger-ui

使用方法

# 1.安装
pip install -U drf-yasg 

# 2.注册
INSTALLED_APPS = [ 
    ... 
    'django.contrib.staticfiles', # required for serving swagger ui's css/js files 
    'drf_yasg', 
    ... 
] 

# 3.总路由
# drf_yasg API
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
    openapi.Info(
        title="Snippets API",
        default_version='v1',
        description="Test description",
        terms_of_service="https://www.google.com/policies/terms/",
        contact=openapi.Contact(email="contact@snippets.local"),
        license=openapi.License(name="BSD License"),
    ),
    public=True,
    permission_classes=[permissions.AllowAny],
)


urlpatterns = [
    # drf_yasg API
    # 这公开了 4 个端点
    # API 规范的 JSON 视图,位于/swagger.json
    # 您的 API 规范的 YAML 视图位于/swagger.yaml
    path('swagger<format>/', schema_view.without_ui(cache_timeout=0), name='schema-json'),

    # API 规范的 swagger-ui 视图位于/swagger/
    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger - ui'),

    # API 规范的 ReDoc 视图位于/redoc/
    path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]

高级功能

1.认证Authentication

Authentication - Django REST framework

1.概念

身份验证是将传入请求与一组标识凭据(例如,请求来自的用户或与其进行签名的令牌)相关联的机制。然后,权限限制策略可以使用这些凭据来确定是否应允许该请求。

身份验证本身不会允许或不允许传入的请求,它只会标识发出请求的凭据。

认证管理一般和权限管理配合使用。

2.认证方式

1.基本认证**(BasicAuthentication)**

此身份验证方案使用HTTP基本身份验证,该身份针对用户的用户名和密码进行了签名。基本身份验证通常仅适用于测试

2.会话认证**(SessionAuthentication)**

此身份验证方案使用Django的默认会话后端进行身份验证。会话身份验证适用于在与您的网站相同的会话上下文中运行的****AJAX****客户端

如果成功通过身份验证request.user将是DjangoUser实例。

未经授权的身份验证的响应将被拒绝HTTP 403 Forbidden

3.令牌认证**(TokenAuthentication)**

此身份验证方案使用简单的基于令牌的HTTP身份验证方案。令牌认证适用于客户端-服务器设置,例如本机台式机和移动客户端

为了使客户端进行身份验证,令牌密钥应包含在AuthorizationHTTP标头中。密钥应以字符串文字“ Token”作为前缀,并用空格分隔两个字符串。例如:

Authorization:Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

认证失败会有两种可能的返回值:
401 Unauthorized 未认证
403 Permission Denied 权限被禁止

3.认证全局设置

因为 认证一般都是和权限配合使用,当我们不设置权限时,是没有任何效果的。为了让大家看到最佳效果,我们额外添加一条配置信息。配置信息的意思是 只有认证登录用户才可以访问视图

REST_FRAMEWORK = {
    # 默认的认证列表: session'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
    ],
    # 默认的权限列表: 只有登录用户才可以访问'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

4.认证指定视图设置

from rest_framework.authentication import TokenAuthentication

class BookModelViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

    #单个视图,设置单独认证方式
    authentication_classes = [TokenAuthentication]

2.权限Permissions

Permissions - Django REST framework

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行对象访问权限的判断

1.提供的权限

  • AllowAny 允许所有用户
  • IsAuthenticated 仅通过认证的用户
  • IsAdminUser 仅管理员用户
  • IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能get读取

2.使用

# DRF 认证全局设置
REST_FRAMEWORK = {
    # 默认的认证列表: session
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
    ],
    # 默认的权限列表: 只有登录用户才可以访问
    'DEFAULT_PERMISSION_CLASSES': (
        # AllowAny 不指定默认 允许所有用户
        # IsAuthenticated 仅通过认证的用户
        # IsAdminUser 仅管理员用户
        # IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能get读取
        'rest_framework.permissions.IsAuthenticated',
    )
}

# 或者
from rest_framework.authentication import TokenAuthentication
class BookModelViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

    #单个视图,设置单独认证方式
    authentication_classes = [SessionAuthentication]

3.指定视图设置

from rest_framework.permissions import AllowAny
class BookViewSet(ViewSet, ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

    # 单个视图,设置单独认证方式
    authentication_classes = [TokenAuthentication]

    # 设置单独的权限
    permission_classes = [AllowAny]

3.分页Pagination

Pagination - Django REST framework

# 全局设置
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10  # 每页数目
}

修改分页样式

class LargeResultsSetPagination(PageNumberPagination):
    page_size = 1000
    page_size_query_param = 'page_size'
    max_page_size = 10000

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 100
    page_size_query_param = 'page_size'
    max_page_size = 1000

# 修改配置文件
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}

可选分页器

1)LimitOffsetPagination

可以在子类中定义的属性:

  • default_limit 默认限制,默认值与PAGE_SIZE设置一致
  • limit_query_param limit参数名,默认'limit'
  • offset_query_param offset参数名,默认'offset'
  • max_limit 最大limit限制,默认None

http://127.0.0.1:8000/books/?limit=2&offset=4

class BookModelViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
    #分页类
    pagination_class = LimitOffsetPagination

2)PageNumberPagination

可以在子类中定义的属性:

  • page_size 每页数目
  • page_query_param 前端发送的页数关键字名,默认为"page"
  • page_size_query_param 前端发送的每页数目关键字名,默认为None
  • max_page_size 前端最多能设置的每页数量

http://127.0.0.1:8000/books/?page=1&pagesize=4

#自定义分页类
class PageNum(PageNumberPagination):
    page_size = 2  # 默认每页返回的条数
    page_size_query_param = 'pagesize'  # url中设置 page_size的键,默认为page_size
    max_page_size = 10  # 每页返回的最大条数


class BookModelViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
    #使用自定义分页类
    pagination_class = PageNum