zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    redis 内存管理与数据淘汰机制(转载)
    Memcached特性及优缺点
    二叉树深度优先遍历和广度优先遍历
    电商 秒杀系统 设计思路和实现方法(转载)
    6种负载均衡算法
    解决like '%字符串%'时索引不被使用的方法
    哪些情况下索引会失效?
    PreferenceActivity详解
    sun.misc.BASE64Encoder在Eclipse中不能直接使用的原因和解决方案
    单点登录原理与简单实现
  • 原文地址:https://www.cnblogs.com/williamweson/p/13634889.html
Copyright © 2011-2022 走看看