• DRF详解


    Django 的DRF框架 Django rest Framework详解

    一、DRF简单操作:

    1、创建序列化器

    class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
    model = BookInfo
    fields = '__all__'

    model 指明该序列化器处理的数据字段从模型类BookInfo参考生成

    fields 指明该序列化器包含模型类中的哪些字段,'__all__'指明包含所有字段

    2、编写视图:

    from rest_framework.viewsets import ModelViewSet
    from .serializers import BookInfoSerializer
    from .models import BookInfo
    class BookInfoViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    queryset 指明该视图集在查询数据时使用的查询集
    serializer_class 指明该视图在进行序列化或反序列化时使用的序列化器

    3、定义路由

     
    from . import views
    from rest_framework.routers import DefaultRouter
    urlpatterns = [
    ...
    ]
    router = DefaultRouter() # 可以处理视图的路由器
    router.register(r'books', views.BookInfoViewSet) # 向路由器中注册视图集
    urlpatterns += router.urls # 将路由器中的所以路由信息追到到django的路由列表中

    4、运行测试:

    python manage.py runserver

    二、定义序列化器Serializer

    1、定义方法:

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

    1.1创建数据库模型类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)

    1.2 为模型类提供一个序列化器(写法一):

    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)

    1.2.1为模型类提供一个序列化器(写法二):

    class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
    model = BookInfo
    fields = '__all__'

    1.3 创建Serializer对象

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

    说明:

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

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

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

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

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

    1.4序列化使用

    1.4.1 查询一个图书对象

    from booktest.models import BookInfo
    book = BookInfo.objects.get(id=2)

    1.4.2 构造序列化器对象

    from booktest.serializers import BookInfoSerializer
    serializer = BookInfoSerializer(book)

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

    serializer.data

    1.4.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')])]

    三、反序列化使用

    1、验证

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

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

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

    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 attra

    测试

    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、保存

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

    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)

    四、模型类序列化器ModelSerializer

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

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

    1、定义

    我们创建一个BookInfoSerializer

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

    2、添加额外字段

    我们可以使用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': {'max_value': 0, 'required': True}},
     }

    五、Request与Response

    1、request

    常用属性:

    1).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,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

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

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

    构造方式

    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会根据前端所需类型数据来设置该参数。

    1).data

    传给response对象的序列化后,但尚未render处理的数据

    2).status_code

    状态码的数字

    3).content

    经过render处理后的响应数据

    六、视图基类

    1、两个基类

    1)APIView

    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

    继承APIView

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

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

    举例:

    # 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)
  • 相关阅读:
    Java实现 LeetCode 167 两数之和 II
    Java实现 LeetCode 1227 飞机座位分配概率
    Java实现 LeetCode 1227 飞机座位分配概率
    Java实现 LeetCode 1227 飞机座位分配概率
    Java实现 LeetCode 166 分数到小数
    QueryPerformanceFrequency 和 QueryPerformanceCounter用法
    VC中利用多线程技术实现线程之间的通信
    C++著名类库和C++标准库介绍
    CRectTracker类的使用--橡皮筋窗口
    备份3个判断指针是否有效的函数,以备不时之需
  • 原文地址:https://www.cnblogs.com/wangtenghui/p/11134729.html
Copyright © 2020-2023  润新知