restframework总体浏览

django-rest-framework

一、序列化

序列化可以把查询集和模型对象转换为json、xml或其他类型,也提供反序列化功
能,也就是把转换后的类型转换为对象或查询集。

REST框架中的序列化程序与Django FormModelForm 类的工作方式非常相似。
我们提供了一个 Serializer类,它为您提供了一种强大的通用方法来控制响应的
输出,以及一个 ModelSerializer类,它提供了一个有用的快捷方式来创建处理模
型实例和查询集的序列化程序。

1.1声明序列化器

from rest_framework import serializers
class xxxSerializer(serializers.Serializer):
     email = serializers.EmailField()
     content = serializers.CharField(max_length=200)
     created = serializers.DateTimeField()

1.2 常用field类

  • 核⼼参数
参数名 缺省值 说明
read_only False 表明该字段仅用于序列化输出,默认False
required True 如果在反序列化期间未提供字段,则会引发错
误。如果在反序列化期间不需要此字段,则设置
为false。
default 缺省值,部分更新时不支持
allow_null False 表明该字段是否允许传入None,默认False
validators [] 验证器,一个函数列表,验证通不过引起
serializers.ValidationError
error_messages {} 一个错误信息字典
  • 常用字段
字段名 说明
BooleanField 对应于django.db.models.fields.BooleanField
CharField CharField(max_length=None, min_length=None,
allow_blank=False,trim_whitespace=True)
max_length - 验证输入包含的字符数不超过此数量。
min_length - 验证输入包含不少于此数量的字符。allow_blank- 如果设置为
True则则应将空字符串视为有效值。如果设置为False则则空字符串被视为无
效并将引发验证错误。默认为False。trim_whitespace- 如果设置为Truethen
则会修剪前导和尾随空格。默认为True
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
IntegerField IntegerField(max_value=None, min_value=None)
max_value 验证提供的数字是否不大于此值。min_value 验证提供的数字是否
不低于此值。
FloatField FloatField(max_value=None, min_value=None)
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT,
input_formats=None, default_timezone=None)
format格式字符串可以是显式指定格式的Python strftime格式
input_formats - 表示可用于解析⽇期的输入格式的字符串列表

1.3 创建Serializer对象

定义好Serializer类后,就可以创建Serializer对象了。Serializer的构造方法为:

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

说明:

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

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

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

serializer = UserSerializer(User, context={'request': request})

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

  • 实例

    #models.py
    class User(models.Model):
         username = models.CharField(max_length=30)
         password_hash =
        models.CharField(max_length=20,db_column='password')
         age = models.IntegerField(default=0)
         class Meta:
         	db_table = 'user'
     
     
    #serializers.py
    def validate_password(password):
         if re.match(r'\d+$',password):
         	raise serializers.ValidationError("密码不能是纯数字")
    class UserSerializer(serializers.Serializer):
         # id = serializers.IntegerField()
         username = serializers.CharField(max_length=30)
         password_hash = serializers.CharField(min_length=3,validators=
        [validate_password])
         age = serializers.IntegerField()
        
        def create(self, validated_data):
     		return User.objects.create(**validated_data)
     def update(self, instance, validated_data):
             instance.username =
            validated_data.get('username',instance.username)
             instance.password_hash =
            validated_data.get('password_hash',instance.password_hash)
             instance.age = validated_data.get('age',instance.age)
             instance.save()
             return instance
            
    #view.py
    class ExampleView(APIView):
    	 def get(self,request):
            # 1.查询数据
             user = User.objects.get(pk=1)
             # 2.构造序列化器
             serializer = UserSerializer(instance=user)
             # 获取序列化数据,通过data属性可以获取序列化后的数据
             print(serializer.data)
             return Response(serializer.data)
    

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

    data = User.objects.all()
    serializer = UserSerializer(instance=data,many=True)
    print(serializer.data)
    

1.4 ModelSerializer

ModelSerializer类能够让你自动创建一个具有模型中相应字段的Serializer类。这
个ModelSerializer类和常规的Serializer类一样,不同的是:

  • 它根据模型自动生成一组字段。
  • 它自动生成序列化器的验证器,比如unique_together验证器。
  • 它默认简单实现了.create()方法和.update()方法。

1. 定义

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

2. 指定字段

  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. 指明只读字段

可以通过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},
         }

1.5 反向序列化

  • 验证

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

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

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

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

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

    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
    
    

    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
    

    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)
    

    1. 保存

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

    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)
    

1.6 关联对象的序列化

如果模型中两个模型有外键关系,如果需要序列化的模型中包含有其他关联对
象,则对关联对象数据的序列化需要指明。例如,在定义英雄数据的序列化器
时,外键hbook(即所属的图书)字段如何序列化?

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

# models.py
class BookInfo(models.Model):
     id = models.AutoField(primary_key=True)
     btitle = models.CharField(max_length=200)
     bpub_date = models.DateField(auto_now_add=True,null=True)
     bread = models.IntegerField(default=0)
     bcomment = models.IntegerField(default=0)
     bimage = models.CharField(max_length=200,null=True)
     class Meta:
     	db_table = 'bookinfo'

        
class HeroInfo(models.Model):
     hid = models.AutoField(primary_key=True)
     hname = models.CharField(max_length=50)
     book =
    models.ForeignKey(BookInfo,db_column='bid',related_name='heros',o
    n_delete=models.CASCADE)
	class Meta:
 		db_table = 'heroinfo'
	def __str__(self):
 		return "{}:{}".format(self.hid,self.hname)

对于外键关联字段,可以采用以下方式:

1. PrimaryKeyRelatedField

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

class HeroInforSerializer(serializers.ModelSerializer):
     class Meta:
     model = HeroInfo
     fields = "__all__"
class BookInfoSerializer(serializers.ModelSerializer):
 	heros = PrimaryKeyRelatedField(many=True,read_only=True)
     class Meta:
         model = BookInfo
         fields = '__all__'
  • many = True,表示可以有多个主键值
  • read_only=True,该字段将不能用作反序列化使用

效果:

[
 	{
     "id": 1,
     "heros": [1,4 ],
     "btitle": "射雕英雄传","bpub_date": "2020-02-18","bread":
    30,
     "bcomment": 80,"bimage": null
 	}, 
]

2. StringRelatedField

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

hbook = serializers.StringRelatedField(many=True,read_only=True)

效果:

[
 	{
     "id": 1,
     "heros": ["1:郭靖","4:⽼顽童"],
     "btitle": "射雕英雄传", "bpub_date": "2020-02-18",
    "bread": 30,"bcomment": 80,
     "bimage": null
 	},
]

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

heros = HeroInforSerializer(many=True,read_only=True)

效果:

[
     {"id": 1,
     "heros": [{"hid": 1, "hname": "郭靖", "book": 1},{"hid": 4,
    "hname": "⽼顽童", "book": 1}],
     "btitle": "射雕英雄传","bpub_date": "2020-02-18","bread": 30,
    "bcomment": 80, "bimage": null
     },
]

⼆、Request和Response

1.Request

REST框架引入了一个扩展了常规HttpRequest的Request对象,并提供了更灵活的
请求解析。Request对象的核⼼功能是request.data属性,它与request.POST类
似,但对于使用Web API更为有用。

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

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

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

1) data属性

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

  • 包含了解析之后的文件和非文件数据
  • 包含了对POST、PUT、PATCH请求方式解析后的数据
  • 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持
    JSON数据
request.POST # 只处理表单数据只适用于'POST'方法
request.data # 处理任意数据 适用于'POST','PUT'和'PATCH'方法

2)query_params 查询参数

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

3)method

request.method 返回请求的HTTP方法的 大写字符串表示形式。

4)自定义解析器

REST framework的请求对象提供灵活的请求解析,允许你以与通常处理表单数据
相同的方式使用JSON数据或其他媒体类型处理请求。

可以使用DEFAULT_PARSER_CLASSES设置全局默认的解析器集。例如,以下设置
将仅允许具有JSON内容的请求,而不是JSON或表单数据的默认值。

REST_FRAMEWORK = {
 'DEFAULT_PARSER_CLASSES': (
 'rest_framework.parsers.JSONParser',
 )
}
你还可以设置用于单个视图或视图集的解析器, 使用APIView类视图。
 from rest_framework.parsers import JSONParser
 from rest_framework.response import Response
 from rest_framework.views import APIView
 class ExampleView(APIView):
     """

    可以接收JSON内容POST请求的视图。
     """
     parser_classes = (JSONParser,)
 	def post(self, request, format=None):
 		return Response({'received data': request.data})
    
或者,如果你使用基于方法的视图的@api_view装饰器。
from rest_framework.decorators import api_view
from rest_framework.decorators import parser_classes

@api_view(['POST'])
@parser_classes((JSONParser,))
def example_view(request, format=None):
     """

    可以接收JSON内容POST请求的视图
     """
     return Response({'received data': request.data})

2.Response

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

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

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

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

3. 状态码(Status codes)

在你的视图(views)中使用纯数字的HTTP 状态码并不总是那么容易被理解。而
且如果错误代码出错,很容易被忽略。REST框架为status模块中的每个状态代码
(如HTTP_400_BAD_REQUEST)提供更明确的标识符。使用它们来代替纯数字的
HTTP状态码是个很好的主意。

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. wrapping

REST框架提供了两个可用于编写API视图的包装器(wrappers)。

  • 用于基于函数视图的@api_view装饰器。
  • 用于基于类视图的APIView类。
from rest_framework.decorators import api_view

@api_view(['GET', 'POST'])
def snippet_list(request): 
	pass

三、基于类的视图(CBV)

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

视图的方法与属性:

1.APIView

APIView是DRF的基类,它支持GET POST PUT DELETE等请求类型,且各种类型的
请求之间,有了更好的分离在进行dispatch分发之前,会对请求进行身份认证,权
限检查,流量控制。APIView有两个:

rest_framework.views.APIView 是REST framework提供的所有视图的基类,继承
自Django的 **View **⽗类。 **APIView **与 **View **的不同之处在于:

  • 传入到视图方法中的是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.mixins

使用基于类的视图的一个最大的好处就是我们可以灵活的选择各种View,使我们
的开发更加的简洁。mixins⾥⾯对应了ListModelMixin,CreateModelMixin,
RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin。

  • CreateModelMixin

    创建视图扩展类,提供 create(request, *args, **kwargs) 方法快速实现创建
    资源的视图,成功返回201状态码。如果序列化器对前端发送的数据验证失
    败,返回400错误。

    • 保存方法perform_create(self, serializer),
    • 成功获取请求头的方法:get_success_headers(self, data)
    # 源码
    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 {}
    
  • ListModelMixin

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

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

    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)
    
    
  • 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)
    
  • 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 aqueryset, 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)
    
  • 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.使用generic

restframework给我们提供了一组混合的generic视图,可以使我们的代码 大大简
化。

GenericAPIView:继承自APIView,增加了对列表视图或者详情视图可能用到的通
用支持方法。通常使用时,可搭配一个或者多个Mixin扩展类。支持定义的属性:

  • 列表视图与详情视图通用:
    • queryset(视图的查询集),
    • serializer_class(视图使用的序列化器)
  • 列表视图专用:
    • pagination_classes(分页控制类)
    • filter_backends(过滤控制)
  • 详情页视图专用:
    • lookup_field(查询单一数据库对象时使用的条件字段,默认为pk)
    • lookup_url_kwarg 查询单一数据时URL中的参数关键字名称,默认
      look_field
      相同

提供的方法:

列表视图与详情视图通用

  • get_queryset: 返回视图使用的查询集,是列表视图与详情视图获取数据的基
    础,默认返回 **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: 返回序列化器对象,被其他视图或扩展类使用,如果我们在视
    图中想要获取序列化器对象,可以直接调用此方法。

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

详情视图使用:

  • get_object: 根据传入的查询参数(lookup_url_kwarg or lookup_field参数)
    获取查询对象,然后返回, 一般进行联合查询时, 需要重写此方法。

    若详情访问的模型类对象不存在,会返回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)
    

列表视图专用:

  • paginate_queryset: 进行分页,返回分页后的单页结果集

提供了5个扩展类:

  • generics.ListAPIView
  • generics.CreateAPIView
  • generic.RetrieveAPIView
  • generic.UpdateAPIView
  • generic.DestroyAPIView

四、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'})
]

action属性

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

例如:

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

一个ViewSet 类当被实例化成一组视图时, 通常会通过使用一个路由类(Router
class)来帮你处理复杂的URL定义,最终绑定到一组处理方法。

路由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
posted @ 2020-09-08 19:59  WillWeson  阅读(110)  评论(0编辑  收藏  举报