DjangoRESTframework

内容摘要
目录1. DjangoRESTframework 1.1 web应用模式 1 前后端不分离 2 前后端分离
文章正文

 

目录
  • 1. DjangoRESTframework
    • 1.1 web应用模式
      • 1 前后端不分离
      • 2 前后端分离
    • 1.1 认识RESTful
    • 1.2 使用Django开发REST 接口
    • 1.3 Django REST framework 简介
  • 2. DRF工程搭建
    • 2.1 环境安装与配置
    • 2.2 使用
  • 3. Serializer序列化器
    • 3.1 定义Serializer
      • 1. 定义方法
      • 2. 字段与选项
        • 通用参数:
      • 3. 创建Serializer对象
    • 3.2 序列化使用
      • 1 基本使用
      • 2 关联对象嵌套序列化
        • 1) PrimaryKeyRelatedField
        • 2) StringRelatedField
        • 3)使用关联对象的序列化器
        • many参数
    • 3.3 反序列化使用
      • 1. 验证
        • 1)validate_
        • 2)validate
        • 3)validators
      • 2. 保存
        • 说明:
    • 3.4 模型类序列化器ModelSerializer
      • 1. 定义
      • 2. 指定字段
      • 3. 添加额外参数
  • 4. 视图
    • 4.1 Request 与 Response
      • 1. Request
      • 常用属性
        • 1).data
        • 2).query_params
      • 2. Response
      • 构造方式
      • 3. 状态码
        • 1)信息告知 - 1xx
        • 2)成功 - 2xx
        • 3)重定向 - 3xx
        • 4)客户端错误 - 4xx
        • 5)服务器错误 - 5xx
    • 4.2 视图概览
    • 4.3 视图说明
      • 1. 两个基类
        • 1)APIView
          • 支持定义的属性:
        • 2)GenericAPIView
          • 支持定义的属性:
          • 提供的方法:
          • get_serializer(self, *args, **kwargs)
      • 2. 五个扩展类
        • 1)ListModelMixin
        • 2)CreateModelMixin
        • 3) RetrieveModelMixin
        • 4)UpdateModelMixin
        • 5)DestroyModelMixin
      • 3. 几个可用子类视图
        • 1) CreateAPIView
        • 2)ListAPIView
        • 3)RetireveAPIView
        • 4)DestoryAPIView
        • 5)UpdateAPIView
        • 6)RetrieveUpdateAPIView
        • 7)RetrieveUpdateDestoryAPIView
    • 4.4 视图集ViewSet
      • 1. action属性
      • 2. 常用视图集父类
        • 1) ViewSet
        • 2)GenericViewSet
        • 3)ModelViewSet
        • 4)ReadOnlyModelViewSet
      • 3. 视图集中定义附加action动作
      • 4. 视图集的继承关系
    • 4.5 路由Routers
      • 1. 使用方法
      • 2. 视图集中包含附加action的
      • 3. 路由router形成URL的方式
  • 5. 其他功能
    • 5.1 版本
    • 5.2 认证Authentication
    • 5.3 权限Permissions
      • 使用
      • 提供的权限
      • 举例
    • 5.4 限流Throttling
      • 使用
      • 可选限流类
      • 实例
    • 5.5 过滤Filtering
    • 5.6 排序
      • 使用方法:
    • 5.7 分页Pagination
      • 可选分页器
        • 1) PageNumberPagination
        • 2)LimitOffsetPagination
    • 5.78 异常处理 Exceptions
      • REST framework定义的异常
    • 5.9 自动生成接口文档
      • 1. 安装依赖
      • 2. 设置接口文档访问路径
      • 3. 文档描述说明的定义位置
      • 4. 访问接口文档网页
        • 两点说明:
    • 5.10 JWT
      • 1 介绍
      • 2 安装
      • 3 案例
    • 5.11 跨域
      • 1 解决跨域:CORS
      • 2 跨域时,发送了2次请求?
      • 3 总结
    • 5.12 paramiko

1. DjangoRESTframework

1.1 web应用模式

在开发Web应用中,有两种应用模式:

  • 前后端不分离
  • 前后端分离

1 前后端不分离

前后端不分离

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

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

2 前后端分离

前后端分离

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

在前后端分离的应用模式中 ,前端与后端的耦合度相对较低。

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

1.1 认识RESTful

1.给别人提供一个URL,根据URL请求方式的不同,做不同操作。
	get,获取
	post,增加
	put,全部更新
	patch,局部更新
	delete,删除
2.数据传输基于json格式。

1.2 使用Django开发REST 接口

Django框架中使用的图书英雄案例来写一套支持图书数据增删改查的REST API接口,

在此案例中,前后端均发送JSON格式数据。

# models
from django.db import models

class BookInfo(models.Model):
    btitle = models.CharField(max_length=20, verbose_name="名称")
    bpub_date = models.DateField(verbose_name="发布日期", null=True)
    bread = models.IntegerField(default=0, verbose_name="阅读量")
    bcomment = models.IntegerField(default=0, verbose_name="评论量")
    image = models.ImageField(upload_to="booktest", verbose_name="图片", null=True)
# urls.py
urlpatterns = [
    url(r"^books/$", views.BooksAPIVIew.as_view()),
    url(r"^books/(?P<pk>d+)/$", views.BookAPIView.as_view())
]
# views.py

from datetime import datetime

class BooksAPIVIew(View):
    """
    查询所有图书、增加图书
    """
    def get(self, request):
        """
        查询所有图书
        路由:GET /books/
        """
        queryset = BookInfo.objects.all()
        book_list = []
        for book in queryset:
            book_list.append({
                "id": book.id,
                "btitle": book.btitle,
                "bpub_date": book.bpub_date,
                "bread": book.bread,
                "bcomment": book.bcomment,
                "image": book.image.url if book.image else ""
            })
        return JsonResponse(book_list, safe=False)

    def post(self, request):
        """
        新增图书
        路由:POST /books/ 
        """
        json_bytes = request.body
        json_str = json_bytes.decode()
        book_dict = json.loads(json_str)

        # 此处详细的校验参数省略

        book = BookInfo.objects.create(
            btitle=book_dict.get("btitle"),
            bpub_date=datetime.strptime(book_dict.get("bpub_date"), "%Y-%m-%d").date()
        )

        return JsonResponse({
            "id": book.id,
            "btitle": book.btitle,
            "bpub_date": book.bpub_date,
            "bread": book.bread,
            "bcomment": book.bcomment,
            "image": book.image if book.image else ""
        }, status=201)


class BookAPIView(View):
    def get(self, request, pk):
        """
        获取单个图书信息
        路由: GET  /books/<pk>/
        """
        try:
            book = BookInfo.objects.get(pk=pk)
        except BookInfo.DoesNotExist:
            return HttpResponse(status=404)

        return JsonResponse({
            "id": book.id,
            "btitle": book.btitle,
            "bpub_date": book.bpub_date,
            "bread": book.bread,
            "bcomment": book.bcomment,
            "image": book.image.url if book.image else ""
        })

    def put(self, request, pk):
        """
        修改图书信息
        路由: PUT  /books/<pk>
        """
        try:
            book = BookInfo.objects.get(pk=pk)
        except BookInfo.DoesNotExist:
            return HttpResponse(status=404)

        json_bytes = request.body
        json_str = json_bytes.decode()
        book_dict = json.loads(json_str)

        # 此处详细的校验参数省略

        book.btitle = book_dict.get("btitle")
        book.bpub_date = datetime.strptime(book_dict.get("bpub_date"), "%Y-%m-%d").date()
        book.save()

        return JsonResponse({
            "id": book.id,
            "btitle": book.btitle,
            "bpub_date": book.bpub_date,
            "bread": book.bread,
            "bcomment": book.bcomment,
            "image": book.image.url if book.image else ""
        })

    def delete(self, request, pk):
        """
        删除图书
        路由: DELETE /books/<pk>/
        """
        try:
            book = BookInfo.objects.get(pk=pk)
        except BookInfo.DoesNotExist:
            return HttpResponse(status=404)

        book.delete()

        return HttpResponse(status=204)

使用Postman测试上述接口

1) 获取所有图书数据

GET 方式访问 http://127.0.0.1:8000/books/, 返回状态码200,数据如下

[
    {
        "id": 1,
        "btitle": "射雕英雄传",
        "bpub_date": "1980-05-01",
        "bread": 12,
        "bcomment": 34,
        "image": ""
    },
    {
        "id": 2,
        "btitle": "天龙八部",
        "bpub_date": "1986-07-24",
        "bread": 36,
        "bcomment": 40,
        "image": ""
    }
]

2)获取单一图书数据

GET 访问 http://127.0.0.1:8000/books/5/ ,返回状态码200, 数据如下

{
    "id": 5,
    "btitle": "西游记",
    "bpub_date": "1988-01-01",
    "bread": 10,
    "bcomment": 10,
    "image": "booktest/xiyouji.png"
}

3)新增图书数据

POST 访问http://127.0.0.1:8000/books/,发送JSON数据:

{
    "btitle": "三国演义",
    "bpub_date": "1990-02-03"
}

返回状态码201,数据如下

{
    "id": 8,
    "btitle": "三国演义",
    "bpub_date": "1990-02-03",
    "bread": 0,
    "bcomment": 0,
    "image": ""
}

4)修改图书数据

PUT 访问http://127.0.0.1:8000/books/8/,发送JSON数据:

{
    "btitle": "三国演义(第二版)",
    "bpub_date": "1990-02-03"
}

返回状态码200,数据如下

{
    "id": 8,
    "btitle": "三国演义(第二版)",
    "bpub_date": "1990-02-03",
    "bread": 0,
    "bcomment": 0,
    "image": ""
}

5)删除图书数据

DELETE 访问http://127.0.0.1:8000/books/8/,返回204状态码

1.3 Django REST framework 简介

  1. 在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写的。
  2. 在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:
    • :校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    • :判断要删除的数据是否存在 -> 执行数据库删除
    • :判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    • :查询数据库 -> 将数据序列化并返回

2. DRF工程搭建

记忆:请求到来之后,先执行视图的dispatch方法。
免除csrf认证
1. 视图(APIView、ListAPIView、ListModelMinx)
2. 版本处理
3. 认证
4. 权限
5. 节流(频率限制)
6. 解析器
7. 筛选器
8. 分页
9. 序列化
10. 渲染

2.1 环境安装与配置

DRF需要以下依赖:

  • Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
  • Django (1.10, 1.11, 2.0)

DRF是以Django扩展应用的方式提供的

pip install djangorestframework -i https:
//pypi.douban.com/simple/

2.2 使用

  • 注册:在settings.pyINSTALLED_APPS中添加"rest_framework"。

    INSTALLED_APPS = [
        "rest_framework"
    ]
    

3. Serializer序列化器

序列化器的作用:

  1. 进行数据的校验
  2. 对数据对象进行转换

3.1 定义Serializer

1. 定义方法

继承自rest_framework.serializers.Serializer。

数据库模型类BookInfo

class BookInfo(models.Model):
    btitle = models.CharField(max_length=20, verbose_name="名称")
    bpub_date = models.DateField(verbose_name="发布日期", null=True)
    bread = models.IntegerField(default=0, verbose_name="阅读量")
    bcomment = models.IntegerField(default=0, verbose_name="评论量")
    image = models.ImageField(upload_to="booktest", verbose_name="图片", null=True)

我们想为这个模型类提供一个序列化器,可以定义如下:

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label="ID", read_only=True)
    btitle = serializers.CharField(label="名称", max_length=20)
    bpub_date = serializers.DateField(label="发布日期", required=False)
    bread = serializers.IntegerField(label="阅读量", required=False)
    bcomment = serializers.IntegerField(label="评论量", required=False)
    image = serializers.ImageField(label="图片", required=False)

注意: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=)

选项参数:

参数名称 作用
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最小值
min_value 最大值

通用参数:

参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息

3. 创建Serializer对象

定义好Serializer类后,就可以创建Serializer对象了。

Serializer的构造方法为:

Serializer(instance=None, data=empty, **kwarg)

说明:

1)用于序列化时,将模型类对象传入instance参数

2)用于反序列化时,将要被反序列化的数据传入data参数

3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

serializer = AccountSerializer(account, context={"request": request})

通过context参数附加的数据,可以通过Serializer对象的context属性获取。

3.2 序列化使用

我们在django shell中来学习序列化器的使用。

python manage.py shell

1 基本使用

1) 先查询出一个图书对象

from booktest.models import BookInfo

book = BookInfo.objects.get(id=2)

2) 构造序列化器对象

from booktest.serializers import BookInfoSerializer

serializer = BookInfoSerializer(book)

3)获取序列化数据

通过data属性可以获取序列化后的数据

serializer.data
# {"id": 2, "btitle": "天龙八部", "bpub_date": "1986-07-24", "bread": 36, "bcomment": 40, "image": None}

4)如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明

book_qs = BookInfo.objects.all()
serializer = BookInfoSerializer(book_qs, many=True)
serializer.data
# [OrderedDict([("id", 2), ("btitle", "天龙八部"), ("bpub_date", "1986-07-24"), ("bread", 36), ("bcomment", 40), ("image", N]), OrderedDict([("id", 3), ("btitle", "笑傲江湖"), ("bpub_date", "1995-12-24"), ("bread", 20), ("bcomment", 80), ("image"ne)]), OrderedDict([("id", 4), ("btitle", "雪山飞狐"), ("bpub_date", "1987-11-11"), ("bread", 58), ("bcomment", 24), ("ima None)]), OrderedDict([("id", 5), ("btitle", "西游记"), ("bpub_date", "1988-01-01"), ("bread", 10), ("bcomment", 10), ("im", "booktest/xiyouji.png")])]

2 关联对象嵌套序列化

如果需要序列化的数据中包含有其他关联对象,则对关联对象数据的序列化需要指明。

例如,在定义英雄数据的序列化器时,外键hbook(即所属的图书)字段如何序列化?

我们先定义HeroInfoSerialzier除外键字段外的其他部分:

class HeroInfoSerializer(serializers.Serializer):
    """英雄数据序列化器"""
    GENDER_CHOICES = (
        (0, "male"),
        (1, "female")
    )
    id = serializers.IntegerField(label="ID", read_only=True)
    hname = serializers.CharField(label="名字", max_length=20)
    hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label="性别", required=False)
    hcomment = serializers.CharField(label="描述信息", max_length=200, required=False, allow_null=True)

对于关联字段,可以采用以下几种方式:

1) PrimaryKeyRelatedField

此字段将被序列化为关联对象的主键。

hbook = serializers.PrimaryKeyRelatedField(label="图书", read_only=True)

指明字段时需要包含read_only=True或者queryset参数:

  • 包含read_only=True参数时,该字段将不能用作反序列化使用

使用效果:

from booktest.serializers import HeroInfoSerializer
from booktest.models import HeroInfo
hero = HeroInfo.objects.get(id=6)
serializer = HeroInfoSerializer(hero)
serializer.data
# {"id": 6, "hname": "乔峰", "hgender": 1, "hcomment": "降龙十八掌", "hbook": 2}

2) StringRelatedField

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

hbook = serializers.StringRelatedField(label="图书")

使用效果

{"id": 6, "hname": "乔峰", "hgender": 1, "hcomment": "降龙十八掌", "hbook": "天龙八部"}

3)使用关联对象的序列化器

hbook = BookInfoSerializer()

使用效果

{"id": 6, "hname": "乔峰", "hgender": 1, "hcomment": "降龙十八掌", "hbook": OrderedDict([("id", 2), ("btitle", "天龙八部")te", "1986-07-24"), ("bread", 36), ("bcomment", 40), ("image", None)])}

many参数

如果关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄HeroInfo对象可能有多个,此时关联字段类型的指明仍可使用上述几种方式,只是在声明关联字段时,多补充一个many=True参数即可。

此处仅拿PrimaryKeyRelatedField类型来举例,其他相同。

在BookInfoSerializer中添加关联字段:

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label="ID", read_only=True)
    btitle = serializers.CharField(label="名称", max_length=20)
    bpub_date = serializers.DateField(label="发布日期", required=False)
    bread = serializers.IntegerField(label="阅读量", required=False)
    bcomment = serializers.IntegerField(label="评论量", required=False)
    image = serializers.ImageField(label="图片", required=False)
    heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)  # 新增

使用效果:

from booktest.serializers import BookInfoSerializer
from booktest.models import BookInfo
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
# {"id": 2, "btitle": "天龙八部", "bpub_date": "1986-07-24", "bread": 36, "bcomment": 40, "image": None, "heroinfo_set": [6,8, 9]}

3.3 反序列化使用

1. 验证

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

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

验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。

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

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

如我们前面定义过的BookInfoSerializer

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label="ID", read_only=True)
    btitle = serializers.CharField(label="名称", max_length=20)
    bpub_date = serializers.DateField(label="发布日期", required=False)
    bread = serializers.IntegerField(label="阅读量", required=False)
    bcomment = serializers.IntegerField(label="评论量", required=False)
    image = serializers.ImageField(label="图片", required=False)

通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证

from booktest.serializers import BookInfoSerializer
data = {"bpub_date": 123}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # 返回False
serializer.errors
# {"btitle": [ErrorDetail(string="This field is required.", code="required")], "bpub_date": [ErrorDetail(string="Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].", code="invalid")]}
serializer.validated_data  # {}

data = {"btitle": "python"}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.errors  # {}
serializer.validated_data  #  OrderedDict([("btitle", "python")])

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

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)

如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:

1)validate_<field_name>

<field_name>字段进行验证,如

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    ...

    def validate_btitle(self, value):
        if "django" not in value.lower():
            raise serializers.ValidationError("图书不是关于Django的")
        return value

测试

from booktest.serializers import BookInfoSerializer
data = {"btitle": "python"}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False   
serializer.errors
#  {"btitle": [ErrorDetail(string="图书不是关于Django的", code="invalid")]}

2)validate

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

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    ...

    def validate(self, attrs):
        bread = attrs["bread"]
        bcomment = attrs["bcomment"]
        if bread < bcomment:
            raise serializers.ValidationError("阅读量小于评论量")
        return attrs

测试

from booktest.serializers import BookInfoSerializer
data = {"btitle": "about django", "bread": 10, "bcomment": 20}
s = BookInfoSerializer(data=data)
s.is_valid()  # False
s.errors
#  {"non_field_errors": [ErrorDetail(string="阅读量小于评论量", code="invalid")]}

3)validators

在字段中添加validators选项参数,也可以补充验证行为,如

def about_django(value):
    if "django" not in value.lower():
        raise serializers.ValidationError("图书不是关于Django的")

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label="ID", read_only=True)
    btitle = serializers.CharField(label="名称", max_length=20, validators=[about_django])
    bpub_date = serializers.DateField(label="发布日期", required=False)
    bread = serializers.IntegerField(label="阅读量", required=False)
    bcomment = serializers.IntegerField(label="评论量", required=False)
    image = serializers.ImageField(label="图片", required=False)

测试:

from booktest.serializers import BookInfoSerializer
data = {"btitle": "python"}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False   
serializer.errors
#  {"btitle": [ErrorDetail(string="图书不是关于Django的", code="invalid")]}

2. 保存

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

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    ...

    def create(self, validated_data):
        """新建"""
        return BookInfo(**validated_data)

    def update(self, instance, validated_data):
        """更新,instance为要更新的对象实例"""
        instance.btitle = validated_data.get("btitle", instance.btitle)
        instance.bpub_date = validated_data.get("bpub_date", instance.bpub_date)
        instance.bread = validated_data.get("bread", instance.bread)
        instance.bcomment = validated_data.get("bcomment", instance.bcomment)
        return instance

如果需要在返回数据对象的时候,也将数据保存到数据库中,则可以进行如下修改

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    ...

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

    def update(self, instance, validated_data):
        """更新,instance为要更新的对象实例"""
        instance.btitle = validated_data.get("btitle", instance.btitle)
        instance.bpub_date = validated_data.get("bpub_date", instance.bpub_date)
        instance.bread = validated_data.get("bread", instance.bread)
        instance.bcomment = validated_data.get("bcomment", instance.bcomment)
        instance.save()
        return instance

实现了上述两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了

book = serializer.save()

如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。

from db.serializers import BookInfoSerializer
data = {"btitle": "封神演义"}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 封神演义>

from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {"btitle": "倚天剑"}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 倚天剑>
book.btitle  # "倚天剑"

说明:

1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到

serializer.save(owner=request.user)

3.4 模型类序列化器ModelSerializer

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()和update()的实现

1. 定义

比如我们创建一个BookInfoSerializer:

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = "__all__"
  • model 指明参照哪个模型类
  • fields 指明为模型类的哪些字段生成

我们可以在python manage.py shell中查看自动生成的BookInfoSerializer的具体实现

>>> from booktest.serializers import BookInfoSerializer
>>> serializer = BookInfoSerializer()
>>> serializer
BookInfoSerializer():
    id = IntegerField(label="ID", read_only=True)
    btitle = CharField(label="名称", max_length=20)
    bpub_date = DateField(allow_null=True, label="发布日期", required=False)
    bread = IntegerField(label="阅读量", max_value=2147483647, min_value=-2147483648, required=False)
    bcomment = IntegerField(label="评论量", max_value=2147483647, min_value=-2147483648, required=False)
    image = ImageField(allow_null=True, label="图片", max_length=100, required=False)

2. 指定字段

"""
model=对应的模型
fields=("参与序列化和反序列的字段1","参与序列化和反序列的字段2")
fields="__all__"    包含所有字段
exclude = ("id", "is_delete")    刨除某些字段
read_only_fields    只能读,不能写
跨表自动深度3种方式(展示外键表的所有字段)
    depth = 1         最大10
                                                # required = False  不是必填传值
    category_txt = serializers.CharField(source="category.name", required=False)

    x1 = serializers.SerializerMethodField()
    def get_x1(self, obj):
        return obj.category.name

显示:删除和发布文字两种方式 (1, "发布"),(2, "删除")
serializers.CharField(source="get_status_display", required=False)
"""
  1. 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = ("id", "btitle", "bpub_date")
  1. 使用exclude可以明确排除掉哪些字段
class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        exclude = ("image",)
  1. 显示指明字段,如:
class HeroInfoSerializer(serializers.ModelSerializer):
    hbook = BookInfoSerializer()

    class Meta:
        model = HeroInfo
        fields = ("id", "hname", "hgender", "hcomment", "hbook")
  1. 指明只读字段

可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = ("id", "btitle", "bpub_date", "bread", "bcomment")
        read_only_fields = ("id", "bread", "bcomment")

3. 添加额外参数

我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = ("id", "btitle", "bpub_date", "bread", "bcomment")
        extra_kwargs = {
            "bread": {"min_value": 0, "required": True},
            "bcomment": {"min_value": 0, "required": True},
        }

# BookInfoSerializer():
#    id = IntegerField(label="ID", read_only=True)
#    btitle = CharField(label="名称", max_length=20)
#    bpub_date = DateField(allow_null=True, label="发布日期", required=False)
#    bread = IntegerField(label="阅读量", max_value=2147483647, min_value=0, required=True)
#    bcomment = IntegerField(label="评论量", max_value=2147483647, min_value=0, required=True)

4. 视图

4.1 Request 与 Response

1. Request

REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。

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

Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。

无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。

常用属性

1).data

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

  • 包含了解析之后的文件和非文件数据
  • 包含了对POST、PUT、PATCH请求方式解析后的数据
  • 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据

2).query_params

request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而已。

2. Response

rest_framework.response.Response

REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

构造方式

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

data数据不要是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer渲染器处理data

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

参数说明:

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

3. 状态码

为了方便设置状态码,REST framewrok在rest_framework.status模块中提供了常用状态码常量。

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

4.2 视图概览

REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。

视图的继承关系:

通用视图继承关系

视图的方法与属性:

视图的方法与属性

4.3 视图说明

1. 两个基类

1)APIView

rest_framework.views.APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
支持定义的属性:
  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类

APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

举例:

from rest_framework.views import APIView
from rest_framework.response import Response

# url(r"^books/$", views.BookListView.as_view()),
class BookListView(APIView):
    def get(self, request):
        books = BookInfo.objects.all()
        serializer = BookInfoSerializer(books, many=True)
        return Response(serializer.data)

2)GenericAPIView

rest_framework.generics.GenericAPIView

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

支持定义的属性:
  • 列表视图与详情视图通用:
    • queryset 列表视图的查询集
    • serializer_class 视图使用的序列化器
  • 列表视图使用:
    • pagination_class 分页控制类
    • filter_backends 过滤控制后端
  • 详情页视图使用:
    • lookup_field 查询单一数据库对象时使用的条件字段,默认为"pk"
    • lookup_url_kwarg 查询单一数据时URL中的参数关键字名称,默认与look_field相同
提供的方法:
  • 列表视图与详情视图通用:

    • get_queryset(self)

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

      def get_queryset(self):
          user = self.request.user
          return user.accounts.all()
      
    • get_serializer_class(self)

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

      def get_serializer_class(self):
          if self.request.user.is_staff:
              return FullAccountSerializer
          return BasicAccountSerializer
      
    • get_serializer(self, *args, **kwargs)

      返回序列化器对象,被其他视图或扩展类使用,如果我们在视图中想要获取序列化器对象,可以直接调用此方法。

      注意,在提供序列化器对象的时候,REST framework会向对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。

  • 详情视图使用:

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

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

      该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。

举例:

# url(r"^books/(?P<pk>d+)/$", views.BookDetailView.as_view()),
class BookDetailView(GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request, pk):
        book = self.get_object()
        serializer = self.get_serializer(book)
        return Response(serializer.data)

2. 五个扩展类

1)ListModelMixin

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

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

源代码:

class ListModelMixin(object):
    """
    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)

举例:

from rest_framework.mixins import ListModelMixin

class BookListView(ListModelMixin, GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request):
        return self.list(request)

2)CreateModelMixin

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

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

源代码:

class CreateModelMixin(object):
    """
    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 {}

3) RetrieveModelMixin

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

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

源代码:

class RetrieveModelMixin(object):
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        # 获取对象,会检查对象的权限
        instance = self.get_object()
        # 序列化
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

举例:

class BookDetailView(RetrieveModelMixin, GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request, pk):
        return self.retrieve(request)

4)UpdateModelMixin

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

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

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

源代码:

class UpdateModelMixin(object):
    """
    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)

5)DestroyModelMixin

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

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

源代码:

class DestroyModelMixin(object):
    """
    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()

3. 几个可用子类视图

1) CreateAPIView

提供 post 方法

继承自: GenericAPIView、CreateModelMixin

2)ListAPIView

提供 get 方法

继承自:GenericAPIView、ListModelMixin

3)RetireveAPIView

提供 get 方法

继承自: GenericAPIView、RetrieveModelMixin

4)DestoryAPIView

提供 delete 方法

继承自:GenericAPIView、DestoryModelMixin

5)UpdateAPIView

提供 put 和 patch 方法

继承自:GenericAPIView、UpdateModelMixin

6)RetrieveUpdateAPIView

提供 get、put、patch方法

继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

7)RetrieveUpdateDestoryAPIView

提供 get、put、patch、delete方法

继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

4.4 视图集ViewSet

使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

  • list() 提供一组数据
  • retrieve() 提供单个数据
  • create() 创建数据
  • update() 保存数据
  • destory() 删除数据

ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。

视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:

class BookInfoViewSet(viewsets.ViewSet):

    def list(self, request):
        ...

    def retrieve(self, request, pk=None):
        ...

在设置路由时,我们可以如下操作

urlpatterns = [
    url(r"^books/$", BookInfoViewSet.as_view({"get":"list"}),
    url(r"^books/(?P<pk>d+)/$", BookInfoViewSet.as_view({"get": "retrieve"})
]

1. action属性

在视图集中,我们可以通过action对象属性来获取当前请求视图集时的action动作是哪个。

例如:

def get_serializer_class(self):
    if self.action == "create":
        return OrderCommitSerializer
    else:
        return OrderDataSerializer

2. 常用视图集父类

1) ViewSet

继承自APIView,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

2)GenericViewSet

继承自GenericAPIView,作用也与GenericAPIVIew类似,提供了get_object、get_queryset等方法便于列表视图与详情信息视图的开发。

3)ModelViewSet

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

4)ReadOnlyModelViewSet

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

3. 视图集中定义附加action动作

在视图集中,除了上述默认的方法动作外,还可以添加自定义动作。

添加自定义动作需要使用rest_framework.decorators.action装饰器。

以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。

action装饰器可以接收两个参数:

  • methods: 该action支持的请求方式,列表传递

  • detail
    表示是action中要处理的是否是视图资源的对象(即是否通过url路径获取主键)
    • True 表示使用通过URL获取的主键对应的数据对象
    • False 表示不使用URL获取主键

举例:

from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    # detail为False 表示不需要处理具体的BookInfo对象
    @action(methods=["get"], detail=False)
    def latest(self, request):
        """
        返回最新的图书信息
        """
        book = BookInfo.objects.latest("id")
        serializer = self.get_serializer(book)
        return Response(serializer.data)

    # detail为True,表示要处理具体与pk主键对应的BookInfo对象
    @action(methods=["put"], detail=True)
    def read(self, request, pk):
        """
        修改图书的阅读量数据
        """
        book = self.get_object()
        book.bread = request.data.get("read")
        book.save()
        serializer = self.get_serializer(book)
        return Response(serializer.data)

url的定义

urlpatterns = [
    url(r"^books/$", views.BookInfoViewSet.as_view({"get": "list"})),
    url(r"^books/latest/$", views.BookInfoViewSet.as_view({"get": "latest"})),
    url(r"^books/(?P<pk>d+)/$", views.BookInfoViewSet.as_view({"get": "retrieve"})),
    url(r"^books/(?P<pk>d+)/read/$", views.BookInfoViewSet.as_view({"put": "read"})),
]

4. 视图集的继承关系

视图集的继承关系

4.5 路由Routers

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

REST framework提供了两个router

  • SimpleRouter
  • DefaultRouter

1. 使用方法

1) 创建router对象,并注册视图集,例如

from rest_framework import routers

router = routers.SimpleRouter()
router.register(r"books", BookInfoViewSet, base_name="book")

register(prefix, viewset, base_name)

  • prefix 该视图集的路由前缀
  • viewset 视图集
  • base_name 路由名称的前缀

如上述代码会形成的路由如下:

^books/$    name: book-list
^books/{pk}/$   name: book-detail

2)添加路由数据

可以有两种方式:

urlpatterns = [
    ...
]
urlpatterns += router.urls

urlpatterns = [
    ...
    url(r"^", include(router.urls))
]

2. 视图集中包含附加action的

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    @action(methods=["get"], detail=False)
    def latest(self, request):
        ...

    @action(methods=["put"], detail=True)
    def read(self, request, pk):
        ...

此视图集会形成的路由:

^books/latest/$    name: book-latest
^books/{pk}/read/$  name: book-read

3. 路由router形成URL的方式

1) SimpleRouter

SimpleRouter

2)DefaultRouter

DefaultRouter

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

5. 其他功能

5.1 版本

可以在配置文件中配置全局默认的版本方案

REST_FRAMEWORK = {
    # 版本配置
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
    "ALLOWED_VERSIONS": ["v1", "v2"],
}

urls

from django.conf.urls import url, include
urlpatterns = [
    # 版本管理
    url(r"^api/(?P<version>w+)/", include("api.urls")),
]

5.2 认证Authentication

可以在配??

代码注释
[!--zhushi--]

作者:喵哥笔记

IDC笔记

学的不仅是技术,更是梦想!