飙血推荐
  • HTML教程
  • MySQL教程
  • JavaScript基础教程
  • php入门教程
  • JavaScript正则表达式运用
  • Excel函数教程
  • UEditor使用文档
  • AngularJS教程
  • ThinkPHP5.0教程

Django REST framework完全入门

时间:2021-12-10  作者:lczmx  

Django REST framework 一个强大灵活的Django工具包,提供了便捷的 REST API 开发框架
我们用传统的django也可以实现REST风格的api,但是顶不住Django REST framework实现起来太简单了

什么REST API风格

主要需要注意这几个:

  1. api部署的域名, 主域名或者专有域名
  2. 版本, 通过url地址或者请求头accept
  3. 路径, 只能有名词, 不能有动词
  4. http请求动词, get, post, update, delete
  5. 状态, 200, 201, 204, 400, 401, 403, 404
  6. 返回json格式数据

例子(仅作参考):

功能 路径 请求方式 响应状态码(成功) 响应体(成功)
获取所有的书籍 /books get 200 OK 全部书籍
创建书籍 /books post 201 Created 已经创建的书籍
获取单个书籍 /books/{id} get 200 OK 单个书籍
修改书籍 /books/{id} put 201 Created 已经修改的单个书籍
删除书籍 /books/{id} delete 204 No Content

详细的可以看这里:RESTful 架构详解
关于返回什么,可以看这里:通用设计规则

简单使用流程

在我看来,Django RST framework的主要工作就是对传统django中的viewform在进行了通用性设计。由于使用REST API,我们可以统一使用一样的请求方式,请求参数和请求体,而响应体和状态码也是确定。所以Django RST framework的复用性极高,而且Django RST framework提供了从简单到复杂的封装类,我们只需要直接使用这些类或继承这些类重写部分方法,就可以享受到便利性和可扩展性。
为了显示Django RST framework简单易用,用展示封装程度比较高的类实现一个五个基本功能(get一个、get全部、post创建、put修改单个、delete删除单个)

  1. 安装Django RST framework

    $pip install djangorestframework
    
  2. 修改setting文件
    域名ALLED_APPS中添加rest_framework

    注:添加这个app可以为我们提供测试页面, 假如是使用postman等工具进行测试的话可以不用添加

  3. 创建model

    from 域名 import models
    
    
    class Author(域名l):
        aid = 域名Field(primary_key=True)
        name = 域名Field(max_length=32, verbose_name="姓名")
        phone = 域名Field(max_length=11, verbose_name="手机号码")
        address = 域名Field(max_length=63, verbose_name="地址")
        def __str__(self):
            return 域名
    
    
  4. 执行迁移命令

    $python 域名 makemigrations
    $python 域名 migrate
    
  5. 定义序列化器
    在app目录下创建一个域名,在里面定义序列化器:

    from 域名alizers import ModelSerializer
    from 域名ls import Author
    
    
    class AuthorSerialize(ModelSerializer):
        class Meta:
            model = Author
            fields = "__all__"
    
    
  6. 使用视图集
    域名中,导入并使用之前的模型和序列化器:

    from 域名sets import ModelViewSet
    
    from 域名alizers import AuthorSerialize
    from 域名ls import Author
    
    
    class AuthorModelViewSet(ModelViewSet):
        queryset = 域名()
        serializer_class = AuthorSerialize
    
    
  7. 定义路由规则
    在根路由中定义urlpatterns:

    """djangotest URL Configuration
    """
    from 域名rib import admin
    from 域名 import path
    from rest_test import views
    from 域名ers import SimpleRouter
    
    urlpatterns = [
    	path(\'admin/\', 域名),
    
    ]
    
    
    router = SimpleRouter()
    
    # 添加自己的url
    域名ster(\'authors\', 域名orModelViewSet, basename="authors")
    urlpatterns += 域名
    
    
  8. 启动django,并访问/authors
    我们就可以看到这样的页面,可以对数据进行增删改查了:
    示意图

序列化器

序列化器的主要作用就是进行数据转换,即序列化(python的数据类型转换为json等数据类型)和反序列化(json等数据类型转换为python的数据类型)
在反序列化的过程中我们还可以手动验证数据是否合法, 可以与model相结合,完成对数据库的操作
所以说,序列化器和djangoForm非常像,所以假如会djangoForm的话,应该很好理解

普通的序列化器

在定程度上可以类比域名

定义起来非常简单,字段名称对应的是model中的字段名,字段类型和model中的字段有一定的对应关系,参数是一些约束条件和描述信息, 见: 字段和参数

from rest_framework import serializers


class AuthorSerialize(域名alizer):
    aid = 域名gerField(read_only=True,label="作者id")
    name = 域名Field(max_length=32, label="姓名")
    phone = 域名Field(min_length=11, max_length=11, label="手机号码")
    address = 域名Field(max_length=63, label="地址")

字段和参数

字段

这里的参数指的是字段自带的参数,不是像required这样都可以用的参数
仅列出常用的

全部字段都是域名alizers下的

字段名称 描述 参数 备注
BooleanField 布尔值 无论有无指定,默认值都为False, NullBooleanField可以接收None的值
CharField 文本 max_length min_length allow_blank(空字符串是否为有效值)trim_whitespace(True时修剪前后的空白,默认为True
EmailField 电子邮箱 max_length min_length allow_blank(默认为False
RegexField 文本,通过正则匹配 regex(正则表达式) max_length min_length allow_blank(默认为False
SlugField regex[a-zA-Z0-9_-]+RegexField字段 就比RegexField少了regex参数
URLField http://<host>/<path>格式的RegexField SlugField
UUIDField uuid字段 format 该字段的format参数指定的是uuid的格式,见UUIDField
IntegerField 整数 max_value min_value
FloatField 小数 max_value min_value
DateTimeField 时间 年月日时分秒 format(序列化的时间格式) input_formats(反序列化的时间格式) default_timezone(时区)

参数

form一样,这里指的是通用的参数,不是字段自带的参数

参数 描述
read_only 只读,不能反序列化,如主键,默认是False
Write_only 只写,不能序列化,只在更新和创建数据时使用,默认是False
required 反序列化必须提供的字段,默认为True
default 默认值,在没有提供值时使用,默认不设置
allow_null 允许值为None(一般情况下,如果向序列化字段传递None是会抛出异常的),默认是False
validators 指定验证器列表
error_message 错误代码到错误消息的字典
label 提供可读性高的字段名称
help_text 对字段进行详细描述

全部字段和参数可以查看官方文档:Serializer fields (中文)、Serializer fields (英文)

序列化操作

书接上回,我们已经在域名中定义了一个AuthorSerialize,下面就利用该序列化器进行序列化,即python的转换为json等数据。

序列化一个

步骤:

  1. 导入AuthorSerializeAuthor模型
  2. 使用get获取Author的数据
  3. 将数据传给AuthorSerializeinstance参数
  4. 使用.data属性(是一个静态属性)获得序列化后的数据

注意:假如你的数据库中没有数据,应该提前将数据创建好,可以用SQL命令也可以用django ORM或借助其他工具

使用django shell执行命令:

$ python 域名 shell
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from 域名alizers import AuthorSerialize
>>> from 域名ls import Author
>>>
>>> a = 域名(pk=4)
>>> t = AuthorSerialize(instance=a)
>>> 域名
{\'aid\': 4, \'name\': \'张三\', \'phone\': \'1388888888\', \'address\': \'广东省广州市xxxxx\'}
>>>

暂时用命令行的方式序列化

序列化多个

序列化器一般是不能序列化多个数据的,需要我们指定参数many=True。同样的,我们先使用django shell执行命令:

$ python 域名 shell
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from 域名alizers import AuthorSerialize
>>> from 域名ls import Author
>>> 
>>> a = 域名()
>>> t = AuthorSerialize(instance=a, many=True)
>>> 
>>> 域名
[OrderedDict([(\'aid\', 4), (\'name\', \'张三\'), (\'phone\', \'138888888888\'), (\'address\', \'广东省广州市xxxx\')]),
OrderedDict([(\'aid\', 5), (\'name\', \'李四\'), (\'phone\', \'1388888888\'), (\'address\', \'广东省广州市xxxxx\')]), 
OrderedDict([(\'aid\', 6),(\'name\', \'王五\'), (\'phone\', \'1388888888\'), (\'address\', \'广东省广州市xxxxx\')])]

可以看到,data的值是一个OrderedDict数据类型

外键序列化

由于外键在序列化时不知道是使用主键、__str__或整个主键的数据中的一个,所以需要我们手动指定不同的字段实现。
假如我们添加了一个model:

class Author(域名l):
    aid = 域名Field(primary_key=True)
    name = 域名Field(max_length=32, verbose_name="姓名")
    phone = 域名Field(max_length=11, verbose_name="手机号码")
    address = 域名Field(max_length=63, verbose_name="地址")

    def __str__(self):
        return 域名
        
        
class Books(域名l):
    bid = 域名Field(primary_key=True)
    name = 域名Field(max_length=32, verbose_name="书名")
    description = 域名Field(max_length=128, verbose_name="书籍描述")
    author = 域名ignKey(Author, on_delete=域名ADE)

    def __str__(self):
        return f"{域名}: 《{域名}》"

子表序列化

子表序列化比较简单,因为字段定义子表哪边,所以可以通过字段,只需要确定返回主表的哪些值即可。

  • 返回外键的主键PrimaryKeyRelatedField
    定义序列化器:

        class BookSerialize(域名alizer):
            bid = 域名gerField(read_only=True)
            name = 域名Field(max_length=32, label="书名")
            description = 域名Field(max_length=128, label="书籍描述")
            author = 域名aryKeyRelatedField(read_only=True)
    
    

    PrimaryKeyRelatedField必须指定read_only为True,或指定queryset=域名(),否则会报错

    使用django shell测试:

    $ python 域名 shell
    Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from 域名alizers import BookSerialize
    >>> from 域名ls import Books
    >>>
    >>> b = 域名()
    >>> s = BookSerialize(instance=b, many=True)
    >>> 域名
    [OrderedDict([(\'bid\', 1), (\'name\', \'book1\'), (\'description\', \'very good\'), (\'author\', 4)]),
    OrderedDict([(\'bid\', 2), (\'name\', \'book2\'), (\'description\', \'好书推荐\'), (\'author\', 4)])]
    >>>
    
    
  • 返回外键的__str__方法StringRelatedField
    修改author的字段类型,让它返回的是主表的__str__方法:

    class BookSerialize(域名alizer):
        bid = 域名gerField(read_only=True)
        name = 域名Field(max_length=32, label="书名")
        description = 域名Field(max_length=128, label="书籍描述")
        author = 域名ngRelatedField(read_only=True)
    
    
    
    

    可以不设置read_only

    验证:

    $ python 域名 shell
    Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from 域名alizers import BookSerialize
    >>> from 域名ls import Books
    >>> 
    >>> b = 域名()
    >>> s = BookSerialize(instance=b, many=True)
    >>> 域名
    [OrderedDict([(\'bid\', 1), (\'name\', \'book1\'), (\'description\', \'very good\'), (\'author\', \'张三\')]), 
    OrderedDict([(\'bid\', 2), (\'name\', \'book2\'), (\'description\', \'好书推荐\'), (\'author\', \'张三\')])]
    
  • 返回整个主表的数据
    只需要字段的值改为主表的序列化器即可:

    class AuthorSerialize(域名alizer):
        aid = 域名gerField(read_only=True)
        name = 域名Field(max_length=32, label="姓名")
        phone = 域名Field(min_length=11, max_length=11, label="手机号码")
        address = 域名Field(max_length=63, label="地址")
    
    
    class BookSerialize(域名alizer):
        bid = 域名gerField(read_only=True)
        name = 域名Field(max_length=32, label="书名")
        description = 域名Field(max_length=128, label="书籍描述")
        author = AuthorSerialize(read_only=True)
    
    

    验证:

    $ python 域名 shell
    Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from 域名alizers import AuthorSerialize, BookSerialize
    >>> from 域名ls import Author, Books
    >>> 
    >>> b = 域名()
    >>> s = BookSerialize(instance=b, many=True)
    >>> 域名
    [OrderedDict([(\'bid\', 1), (\'name\', \'book1\'), (\'description\', \'very good\'), 
    (\'author\', OrderedDict([(\'aid\', 4), (\'name\', \'张三\'), (\'phone\', \'138888888888\'), (\'address\', \'广东省广州市xxxxx\')]))]), 
    OrderedDict([(\'bid\', 2), (\'name\', \'book2\'), (\'description\', \'好书推荐\'), 
    (\'author\', OrderedDict([(\'aid\', 4), (\'name\', \'张三\'), (\'phone\', \'138888888888\'), (\'address\', \'广东省广州市xxxxx\')]))])]
    

主表序列化

由于主表不能直接访问子表,但是我们知道django为我们提供了表名(小写)_set管理器,这样我们就可以通过该管理器访问子表了。

假如指定了related_name参数的话,该管理器的名称就是related_name的值
如可以改成这样:author = 域名ignKey(Author, on_delete=域名ADE, related_name="author")
另,关于管理器,可以查看django的文档:“反向” 关联和管理器

为了演示,使用默认的管理器

与子表类似,我们需要指定返回什么值(__str__或主键),使用的是相同的字段,但是要指定many参数!!

  • __str__ StringRelatedField

    注意many参数

    序列化器:

    class AuthorSerialize(域名alizer):
        aid = 域名gerField(read_only=True)
        name = 域名Field(max_length=32, label="姓名")
        phone = 域名Field(min_length=11, max_length=11, label="手机号码")
        address = 域名Field(max_length=63, label="地址")
        books_set = 域名ngRelatedField(read_only=True, many=True)
    
    

    演示:

    $ python 域名 shell
    Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from 域名alizers import AuthorSerialize
    >>> from 域名ls import Author
    >>> 
    >>> a = 域名(pk=4)
    >>> t = AuthorSerialize(instance=a)
    >>> 域名
    {\'aid\': 4, \'name\': \'张三\', \'phone\': \'138888888888\', \'address\': \'广东省广州市xxxxx\', \'books_set\': [\'张三: 《book1》\', \'张三: 《book2》\']}
    
  • 主键PrimaryKeyRelatedField

    注意many参数

    序列化器:

    class AuthorSerialize(域名alizer):
        aid = 域名gerField(read_only=True)
        name = 域名Field(max_length=32, label="姓名")
        phone = 域名Field(min_length=11, max_length=11, label="手机号码")
        address = 域名Field(max_length=63, label="地址")
        books_set = 域名aryKeyRelatedField(read_only=True,many=True)
    
    

    演示:

    $ python 域名 shell
    Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from 域名alizers import AuthorSerialize
    >>> from 域名ls import Author
    >>> 
    >>> a = 域名(pk=4)
    >>>
    >>> t = AuthorSerialize(instance=a)
    >>> 域名
    {\'aid\': 4, \'name\': \'张三\', \'phone\': \'138888888888\', \'address\': \'广东省广州市xxxxx\', \'books_set\': [1, 2]}
    >>>
    

反序列化操作

上面演示了如何将model序列化成 字符串或OrderedDict,而反序列化化就是将json等数据,变成序列化器中的字段的数据类型,就好比我们使用form处理数据一样。

一般操作

此部分还不涉及将数据保存到数据库

流程:

  1. 获得数据
  2. 将数据传入到序列化器的data参数中
  3. 调用返回对象的is_valid()方法

由于还未讲到视图,所以先用一个字典数据代替从浏览器传过来的数据。

$python 域名 shell
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from 域名alizers import AuthorSerialize, BookSerialize
>>> from 域名ls import Author, Books
>>>
>>> data = {
...     "name": "龙傲天",
...     "phone": "18888888888",
...     "address": "xxx省xx市",
... }
>>>
>>> result = AuthorSerialize(data=data)
>>> 域名alid(raise_exception=True)
True

# ################ 这里故意用一个错误的数据 #############################
>>> data = {
...     "name": "龙傲天",
...     "phone": "188888888889",
...     "address": "xxx省xx市",
... }
>>> result = AuthorSerialize(data=data)
>>> 域名alid(raise_exception=True)
# 报错
域名dationError: {\'phone\': [ErrorDetail(string=\'Ensure this field has no more than 11 characters.\', code=\'max_length\')]}
>>>
  • is_validdjango formis_valid一样,可以检验数据是否符合我们在序列化器中定义的一样,检验成功是返回True,否则返回False
  • 假如指定raise_exceptionTrue,那么当数据不合法时,抛出异常,我们可以通过error_messages参数提示信息(见: 自定义错误信息)。
  • 假如不想要抛出异常,我们也可以通过.errors获取错误信息(这是一个OrderedDict的子类对象)如这里的域名rs

利用序列化器进行创建和更新数据

终于讲到如何将数据保存到数据库了。

用过django ModelForm的都知道,只要将数据传入到form中,假如数据通过,就可以通过.save()方法将数据保存到数据库,指定instance参数可一个更新数据。而序列化器的使用方式样是这样,不过我们现在用的是叫较为低级的序列化器,需要我们自定义创建数据和更新数据的逻辑

创建数据

使用步骤:

  1. 获得数据
  2. 将数据传入到序列化器的data参数中
  3. 调用返回对象的is_valid()方法
  4. 为序列化器定义create方法
  5. 调用save方法,执行创建数据的函数(会调用create函数)

这里的create函数需要我们自定义,在序列化器中:

class AuthorSerialize(域名alizer):
    aid = 域名gerField(read_only=True)
    name = 域名Field(max_length=32, label="姓名")
    phone = 域名Field(min_length=11, max_length=11, label="手机号码")
    address = 域名Field(max_length=63, label="地址")
    books_set = 域名ngRelatedField(read_only=True, many=True)

    def create(self, validated_data):
        """
        创建数据
        :param validated_data: 已经通过验证的数据
        :return: Author instance
        """
        author = 域名te(**validated_data)
        
        # 不要忘记返回数据了
        return author
        

可以说非常简单,下面有django shell测试一下:

$python 域名 shell
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from 域名alizers import AuthorSerialize
>>> 
>>> data = {
...     "name": "龙傲天",
...     "phone": "18888888888",
...     "address": "xxx省xx市",
... }
>>> result = AuthorSerialize(data=data)
>>> 域名alid(raise_exception=True)
True
>>> 域名()
<Author: 龙傲天>

用PyCharm自带的Database工具,我们可以看到的确已经保存到了数据库中:
示意图

更新数据(全部)

PUT请求方式是更新全部数据

使用步骤:

  1. 获得数据
  2. 将数据传入到序列化器的data参数中, 要更新的数据传入instance参数
  3. 调用返回对象的is_valid()方法
  4. 为序列化器定义update方法
  5. 调用save方法,执行创建数据的函数(会调用update函数)

只要序列化器中同时传入datainstance参数,它就会调用更新的方法(update)

注意:data参数传入数据,instance参数传入待更新的model对象

class AuthorSerialize(域名alizer):
    aid = 域名gerField(read_only=True)
    name = 域名Field(max_length=32, label="姓名")
    phone = 域名Field(min_length=11, max_length=11, label="手机号码")
    address = 域名Field(max_length=63, label="地址")
    books_set = 域名ngRelatedField(read_only=True, many=True)

    def update(self, instance, validated_data):
        """
        更新数据
        由于传入的不是QuerySet对象,所以不能用update方法
        :param instance: Author对象
        :param validated_data: 已经验证的数据
        :return: instance
        """
        域名 = 域名("name")
        域名e = 域名("phone")
        域名ess = 域名("address")
        域名()  # 不要忘记保存了

        return instance

$ python 域名 shell
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from 域名alizers import AuthorSerialize
>>> from 域名ls import Author
>>> 
>>> author = 域名(pk=10)
>>> 
>>> data = {
...     "name": "龙傲天",
...     "phone": "18888888888",
...     "address": "广东省广州市",
... }
>>> result = AuthorSerialize(data=data, instance=author)
>>> 域名alid(raise_exception=True)
True
>>> 域名()
<Author: 龙傲天>
>>>

更新数据(部分)

PATCH请求方式是更新部分数据

上面我们只更新了地址的信息,却把其它不用改的信息也一并穿了进去,这显然不是我们预期的,但由于序列化器的字段的required默认为True,除非我们设置read_only=True或指定一个默认值,否则会报错,但设置了这些又会影响到我们正常创建数据的验证。
所以,序列化器提供了一个参数:partial用来说明这是更新部分信息的。在使用时和上面的一样,只是多了个参数而已。不过我们需要修改一下update函数, 因为值可能为None, 会报错,可以指定get的默认值,也可以用反射的方法:


class AuthorSerialize(域名alizer):
    aid = 域名gerField(read_only=True)
    name = 域名Field(max_length=32, label="姓名")
    phone = 域名Field(min_length=11, max_length=11, label="手机号码")
    address = 域名Field(max_length=63, label="地址")
    books_set = 域名ngRelatedField(read_only=True, many=True)

    def update(self, instance, validated_data):
        """
        更新数据
        :param instance: Author对象
        :param validated_data: 已经验证的数据
        :return: instance
        """
        for field in validated_data:
            if not hasattr(instance, field):
                continue
            setattr(instance, field, 域名(field))

        域名()  # 不要忘记保存了
        return instance

来试一下吧:

$ python 域名 shell
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from 域名alizers import AuthorSerialize
>>> from 域名ls import Author
>>> 
>>> data = {
...     "address": "广东省广州市xxxxx",
... }
>>> author = 域名(pk=10)
>>> result = AuthorSerialize(data=data, instance=author, partial=True)
>>> 域名alid(raise_exception=True)
True
>>> 域名()
<Author: 龙傲天>

Model的序列化器

DRF有一个model序列化器: ModelSerializer, 其在一定程度上与域名lForm十分相似
在上面使用的例子就用到了该序列化器

说到底,它就是将干了这几件事:

  1. 我们的model字段根据对应关系转化为serializers中的字段
  2. 将model字段的约束条件变为serializers字段的约束条件
  3. 内置了create方法和update方法

简单使用

简直是简简单单:

class AuthorModelSerialize(域名lSerializer):
    class Meta:
        model = Author
        fields = "__all__"

Meta类

从例子中看出,Meta类是关键,它决定着 要序列化的字段、用哪个模型、错误信息、约束条件等重要的参数。
下面我们看看Meta类可以指定什么内容:

还是那句话,真的和ModelForm十分相似

  1. model
    指定用哪个Model
  2. fields
    使用模型中的哪些字段,推荐利用元组显式指定,但可以将值指定为__all__(表示全部字段)
    不能和exclude一起使用,否则报错:Cannot set both \'fields\' and \'exclude\' options on serializer xxx.
  3. exclude
    不使用模型中的哪些字段
    不能和fields一起使用,否则报错:Cannot set both \'fields\' and \'exclude\' options on serializer xxx.
  4. depth
    指定关联深度,是一个数字
    注意,关联字段默认返回的是主键,即域名aryKeyRelatedField
  5. read_only_fields
    只读字段,主键默认只读
  6. extra_kwargs
    指定额外的参数,该参数可以传给字段

例子:

class AuthorModelSerialize(域名lSerializer):
    class Meta:
        model = Author      # 指定使用Author这个模型
        # 指定字段,注意:books_set
        fields = ("aid", "name", "phone", "address", "books_set")

        # 不使用模型中的哪些字段
        # 不能一起使用,这里注释掉
        
        # exclude = ("phone", )
        
        depth = 1       # 关联深度为1
        # 设置只读字段
        read_only_fields = ("aid", "books_set")

        # 设置额外参数,该参数是给字段的
        # 注意格式
        extra_kwargs = {
            "name": {
                "read_only": True
            }
        }

我们同样用django shell查看:

$ python 域名 shell
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC 域名 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from 域名alizers import AuthorModelSerialize
>>> from 域名ls import Author
>>> 
>>> a = 域名()
>>> res = AuthorModelSerialize(instance=a, many=True)
>>> res
AuthorModelSerialize(instance=<QuerySet [<Author: 张三>, <Author: 李四>, <Author: 王五>, <Author: 龙傲天>]>, many=True):aid = IntegerField(read_only=True) name = CharField(label=\'姓名\', read_only=True) address = CharField(label=\'地址\', max_length=63) books_set = NestedSerializer(many=True, read_only=True): bid = IntegerField(read_only=True) name = CharField(label=\'书名\', max_length=32) description = CharField(label=\'书籍描述\', max_length=128) author = PrimaryKeyRelatedField(queryset=域名())

extra_kwargs

由于ModelSerializer直接用model的字段类型,肯定不能很好的做好条件约束
因此DRF提供了extra_kwargs属性, 并且错误信息也通过该参数进行自定制

class AuthorModelSerialize(域名lSerializer):
    class Meta:
        model = Author  # 指定使用Author这个模型
        # 指定字段,注意:books_set
        fields = ("aid", "name", "phone", "address", "books_set")
        extra_kwargs = {
            "phone": {
                "min_length": 11,
                "max_length": 11
            }
        }

像普通Serialize那样编写

我们可以自定义一些额外的字段或不用extra_kwargs属性而直接model的字段进行定义:

class AuthorModelSerialize(域名lSerializer):
    phone = 域名Field(min_length=11, max_length=11, label="手机号码")
	# write_only只反序列化,不入库
    note = 域名Field(max_length=128, label="额外的字段,不入库", write_only=True)    

    class Meta:
        model = Author  # 指定使用Author这个模型
        # 指定字段,注意:books_set
        fields = ("aid", "name", "address", "books_set")

指定外键返回类型

外键默认返回主键,但通过serializer_related_field属性指定:

class AuthorModelSerialize(域名lSerializer):
    serializer_related_field = 域名ngRelatedField        
	# 返回 __str__

    class Meta:
        model = Author
        fields = ("aid", "name", "address", "books_set")

验证数据

这部分内容也是和Model一样

验证一个字段

form一样,只要在序列化器重定义一个validate_xxx方法(xxx指的是字段名)即可验证单个字段,如下面的例子:

class AuthorSerialize(域名alizer):
    aid = 域名gerField(read_only=True)
    name = 域名Field(max_length=32, label="姓名")
    phone = 域名Field(min_length=11, max_length=11, label="手机号码")
    address = 域名Field(max_length=63, label="地址")
    books_set = 域名ngRelatedField(read_only=True, many=True)

    def validate_name(self, value:str):
        # 1. 判读
        if not 域名tswith("lcz"):
            # 抛出ValidationError异常
            raise 域名dationError("必须以lcz开头", "startError")
        # 2.返回结果
        return value

ValidationError是一个异常,有两个参数detailcode,前者接收异常的描述信息,后者接收异常名(默认为"invalid"
该方法调用is_valid时自动执行
记得返回value

验证一下:

>>> data = {
...     "name": "xxx",
...     "phone": "12345678910",
...     "note": "test",
...     "address": "广东省广州市xxxxx1",
... }
>>> result = AuthorSerialize(data=data)
>>> 域名alid()
False
>>> 域名rs
{\'name\': [ErrorDetail(string=\'必须以lcz开头\', code=\'startError\')]}

验证多个字段

需要重写validate方法:

class AuthorSerialize(域名alizer):
    aid = 域名gerField(read_only=True)
    name = 域名Field(max_length=32, label="姓名")
    phone = 域名Field(min_length=11, max_length=11, label="手机号码")
    address = 域名Field(max_length=63, label="地址")
    books_set = 域名ngRelatedField(read_only=True, many=True)

    def validate(self, attrs):
        """
        :param attrs: 外界传入的需要校验的字典
        :return: attrs
        """
        # 1. 判断name和address(随便举个例子)
        if attrs["name"].startswith("lcz") and 域名tswith("广东省"):
            # 2.返回结果
            return attrs
        # 否则抛出异常
        raise 域名dationError("只有lcz开头且地址是广东省的才能通过验证")

自定义验证器

分两步:

  1. 定义
    使用验证器时,传入的数据已经转换为python的数据类型
    def check_bpub_date(date):
    	if 域名 < 2015:
    		raise 域名dationError("日期不能小于2015年")
    
    	return date
    
  2. 使用
    通过validators参数指定
    def check_pub_date(date):
    	if 域名 < 2015:
    		raise 域名dationError("日期不能小于2015年")
    	return date
    
    
    class BookSerialize(域名alizer):
    	pub_date = 域名TimeField(validators=[check_pub_date]
    
    

注:ModelSerialize通过extra_kwargs属性指定

自定义错误信息

  1. 内置错误通过error_messages参数指定
  2. 手动抛出的异常,通过异常信息指定

错误信息是可以用一个函数专门处理的,详情请看: 异常处理

如:

from rest_framework import serializers


class AuthorSerialize(域名alizer):
    aid = 域名gerField(read_only=True)
    name = 域名Field(max_length=32, label="姓名")
    phone = 域名Field(min_length=11, max_length=11, label="手机号码",
                                  error_messages={"min_length": "号码太短了", "max_length": "号码太长了"})
    address = 域名Field(max_length=63, label="地址")
    books_set = 域名ngRelatedField(read_only=True, many=True)

和使用ValidationError的值定义为错误信息:

def check_bpub_date(date):
    if 域名 < 2015:
        raise 域名dationError("日期不能小于2015年")
    return date

视图

Django REST framework的视图种类比序列化器还多,从一级视图到视图集,每一个都是在之前的视图基础上进行了封装,至于用哪个,全凭自己的喜好了。
详情见下图:
DRF视图

Django REST framework的视图都是用CBV的写法

由于REST API的url是固定的,所以可以把视图分为 列表视图和详情视图,可能有点抽象,举个例子:

  • 列表视图:GET /books(获取所有的书籍);POST /books (创建书籍)
  • 详情视图:GET /books/{id}(获取单个书籍 );PUT /books/{id}(修改书籍);DELETE /books/{id} (删除书籍)

可以感受出来了吧,对数据做增删改查需要两个路由5个函数, 因此我们可以将由于视图类分为 列表视图 和 详情视图两个视图类,不过我们可以利用 视图集 将视图类变为一个

request和responses

django中任何视图必然至少接收一个request,返回一个responseDjango REST framework也不例外。

request

DRFRequest类扩展了django默认的HttpRequest,它主要有两个属性:

  1. 域名
    得到请求体的数据(表单数据和JSON数据都行)
  2. 域名y_params
    得到查询数据(任何HTTP方法类型可能包括查询参数,而不仅仅是GET请求

除此外还有关于认证等属性,由于与django原来的request类似, 故这里不展开

responses

Response的签名:Response(data, status=None, template_name=None, headers=None, content_type=None)
一般我们只需要用到前两个参数即可:

  • data: response的数列化数据
  • status: response的状态码。默认是200
  • template_name: HTMLRenderer 选择要使用的模板名称
  • headers: `响应头,是一个字典
  • content_type: response的内容类型。通常由渲染器自行设置

常用状态码

你可以在域名us中找到所有状态码

代码变量 对应状态码 说明
HTTP_200_OK 200 请求成功
HTTP_201_CREATED 201 该请求已成功,并因此创建了一个新的资源, 一般为POSTPUT成功后返回
HTTP_204_NO_CONTENT 204 服务器成功处理了请求,但不需要返回任何实体内容, 一般为DELETE成功后返回
HTTP_400_BAD_REQUEST 400 语义有误,当前请求无法被服务器理解 或 请求参数有误
HTTP_401_UNAUTHORIZED 401 当前请求需要用户验证
HTTP_403_FORBIDDEN 403 服务器已经理解请求,但是拒绝执行它
HTTP_404_NOT_FOUND 404 请求失败,请求所希望得到的资源未被在服务器上发现
HTTP_500_INTERNAL_SERVER_ERROR 500 服务器遇到了不知道如何处理的情况
HTTP_502_BAD_GATEWAY 502 服务器作为网关需要得到一个处理这个请求的响应,但是得到一个错误的响应
HTTP_503_SERVICE_UNAVAILABLE 503 服务器没有准备好处理请求。 常见原因是服务器因维护或重载而停机

一级视图APIView

域名iew域名域名的子类,用起来和普通的传统的继承View的写法差不多

列表视图

列表视图的写法:

  1. 定义一个类,继承APIView
  2. 定义方法(get, post
  3. request中获取数据
  4. 利用 序列化器 序列化数据或检验数据入库
  5. 返回(除非抛出异常,否则返回的都是data的数据)
from 域名s import APIView
from rest_framework import status
from 域名onse import Response
from 域名alizers import AuthorModelSerialize
from 域名ls import Author


class AuthorListView(APIView):
    def get(self, request):
        """
        获取全部数据
        :param request: 
        :return: 
        """
        authors = 域名()
		# instance指定要序列化的对象
		# 多个数据用many=True
        serialize = AuthorModelSerialize(instance=authors, many=True)
        return Response(域名, status=域名_200_OK)

    def post(self, request):
        """
        创建数据
        :param request: 
        :return: 
        """
        serialize = AuthorModelSerialize(data=域名)
        
        # raise_exception=True,假如报错,会自动处理
        # 返回状态码:400,且数据的形式:{"phone": ["Ensure this field has no more than 11 characters."]}
        
        域名alid(raise_exception=True)
        域名()
        return Response(域名, status=域名_201_CREATED)

别忘了写路由规则:

from 域名rib import admin
from 域名 import path
from rest_test import views

urlpatterns = [
    path(\'admin/\', 域名),
	# 同样调用.as_view方法
    path("authors/", 域名iew())
]

详情视图

在原来的基础上多了主键,用来操作单个数据:

  1. 同样继承APIView
  2. 定义get put delete四个方法
  3. 使用get_object_or_404取得要操作的对象(不用我们处理异常)
  4. 返回数据
from 域名s import APIView
from rest_framework import status
from 域名onse import Response
from 域名alizers import AuthorModelSerialize
from 域名ls import Author
from 域名tcuts import get_object_or_404


class AuthorDetailView(APIView):
    def get(self, request, pk):
        # 这是django的内置方法,不会的可以查一下
        author = get_object_or_404(Author, pk=pk)

        serialize = AuthorModelSerialize(instance=author)
        return Response(域名, status=域名_200_OK)

    def put(self, request, pk):
        author = get_object_or_404(Author, pk=pk)
		
        # 兼容patch方法的部分更新,一般我们都不会在定义个patch方法
        serialize = AuthorModelSerialize(instance=author, data=域名, partial=True)
        域名alid(raise_exception=True)
        域名()
        ret                
标签:编程
湘ICP备14001474号-3  投诉建议:234161800@qq.com   部分内容来源于网络,如有侵权,请联系删除。