DRF 框架学习小结

18 篇文章 0 订阅

前言:

django restful framework框架,继续学习中。发现了一篇不错的文章。


1、 RESTful是一种API的命名风格。
2、 前后端分离: 用户访问静态文件的服务器,数据全部由ajax请求给到。
3、 RESTful风格:数据应该是名词,而动词由HTTP的请求方式来体现。
4、 RESTful风格的API给前端返回结果对象,无论什么请求方式。

'''
特点: 反复重复
因为不论什么请求方式,都需要给前端返回对象内容,就是json格式的
所以每次如果有查询的结果对象都需要遍历成字典,和flask相同

如果不是get请求是带有内容的请求,那从前端接收的是json格式
每次都需要从request.body中拿出内容,是bytes格式
然后decode解码成json字符串然后再loads成可以给python处理的字典
'''

'''
说明:
return JsonResponse(book_list, safe=False)
# 对safe的说明,我们传过去的book_list是一个list格式
# 在前端json支持{}格式也支持[]格式
# 但是django中认为[]的json格式是不安全的会进行校验
# 所以把safe选项关闭False,不进行校验就可以传[]
'''

'''
序列化:对查询结果进行遍历,然后转成字典,给到JsonResponse
反序列化:接收前端json处理成字典,然后校验
'''

'''

正文:


1.DRF框架工程搭建,建立在django的基础上
安装DRF: pip install djangorestframework
注册DRF: INSTALLED_APPS = ['rest_framework',]
在子应用中serializers.py创建序列化器,用于执行序列化和反序列化
在views中类视图使用序列化器,在urls中写地址
'''

'''
2.序列化器: serializer

定义: 其实ModelSerializer是Serializer的子类,更方便有模型类的序列化器的创建,实际产生的序列化器如下
class BookInfoSerializer(serializers.Serializer):   实际继承Serializer
    """图书数据序列化器"""      序列化器:执行序列化和反序列化
    id = serializers.IntegerField(label='ID', read_only=True)     read_only:只在输出响应中使用,就是给前端的时候,而前端给我们传请求的时候,不做验证
    btitle = serializers.CharField(label='名称', max_length=20)
    bpub_date = serializers.DateField(label='发布日期', required=False)
    bread = serializers.IntegerField(label='阅读量', required=False)
    bcomment = serializers.IntegerField(label='评论量', required=False)
    image = serializers.ImageField(label='图片', required=False)
    
字段 : 跟模型类创建很相似,具体存在的字段见讲义   还有常用的参数(就是约束)

使用: 创建对象 serializer = Serializer(instance=None, data=empty, **kwarg)
             说明: 序列化时,将模型类对象传入instance参数   instance = 序列化对象
                    反序列化时,将要被反序列化的数据传入data参数    data = 反序列化对象
                    可通过context参数额外添加数据 即 **kwarg : context={'request': request}  通过Serializer对象的context属性获取
'''

'''
3.序列化操作 : 其实就是查询到对象之后,遍历构造字典的过程,而JsonResponse由内置的 Renderer渲染器来执行

3-1.序列化只使用序列化器对象的第一个参数instance
serializer = BookInfoSerializer(instance = book)
通过data属性可以获取序列化后的数据,这个data跟第二个参数可不是一个
serializer.data
# {'id': 2, 'btitle': '天龙八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image': None}


3-2.如果要被序列化的是包含多条数据的查询集QuerySet,添加many=True参数
book_qs = BookInfo.objects.all()
serializer = BookInfoSerializer(book_qs, many=True)
serializer.data
'''

'''
4.关联对象嵌套序列化(由hero->book通过 hbook方法)

4-1.hbook是个外键: PrimaryKeyRelatedField
hbook = serializers.PrimaryKeyRelatedField(label='图书', read_only=True)
因为是外键,第二个位置必须有read_only=True 或者 查询集 queryset=BookInfo.objects.all() 要不报错
serializer.data 序列化的时候 结果是 关联对象的主键 {'hbook': 2}   即 book.id

4-2.因为id不直观,想要详细内容的字符串,把外键字段改为 :  StringRelatedField
hbook = serializers.StringRelatedField(label='图书')
结果: {'hbook': '天龙八部'}

4-3.接口链接: HyperlinkedRelatedField
hbook = serializers.HyperlinkedRelatedField(label='图书', read_only=True, view_name='books-detail')
必须指明view_name参数,以便DRF根据视图名称寻找路由,进而拼接成完整URL   这个view_name传什么:url中有1个参数,是命名空间,是跟它关联 
结果: {'hbook': 'http://127.0.0.1:8000/books/2/'}

4-4.关联对象的指定字段数据 :  SlugRelatedField
hbook = serializers.SlugRelatedField(label='图书', read_only=True, slug_field='bpub_date')
slug_field指明使用关联对象的哪个字段
结果:{'hbook': datetime.date(1986, 7, 24)}

4-5.使用关联对象的序列化器:  直接把所属book的所有内容序列化
hbook = BookInfoSerializer()
结果:{'hbook': OrderedDict([('id', 2), ('btitle', '天龙八部')te', '1986-07-24'), ('bread', 36), ('bcomment', 40), ('image', None)])}

 

'''
5.重写to_representation方法
序列化器的每个字段实际都是由该字段的to_representation方法决定展示格式的,可以通过重写该方法来决定格式
注意,to_representations方法不仅局限在控制关联对象格式上,适用于各个序列化器字段类型
class BookRelateField(serializers.RelatedField):
    """自定义新的关联字段"""
    def to_representation(self, value):
        return 'Book: %d %s' % (value.id, value.btitle)


hbook = BookRelateField(read_only=True)
结果:{'hbook': 'Book: 2 天龙八部'}

重点: 上边的都是 多对一 关系 即使用hbook
    如果是 一对多 关系 即使用 heroinfo_set.all  此时关联字段类型通用,即上边的字段通用,但是需要添加many=True的参数
heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)  

'''

'''
6.反序列化 : 接收前端传过来的json处理是由 Parser解析器 来执行,反序列化只进行验证和保存

使用: 
data = {'bpub_date': 123}
serializer = BookInfoSerializer(data=data)  构造对象,第一个参数instance不传,传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  # {}         标题没传,时间写错,当然获取不到,验证都没通过

6-1.验证 is_valid()方法
(1)报错:  序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误
        非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名
把报错给前端,显示HTTP 400 Bad Request请求错误 : is_valid(raise_exception=True) 开启参数      

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

(3)自定义验证,在执行is_valid时验证

(3-1)validate_<field_name> : 对字段进行验证
class BookInfoSerializer(serializers.Serializer):
    def validate_btitle(self, value):   验证btitle字段,value是传入的btitle值
        if 'django' not in value.lower():
            raise serializers.ValidationError("图书不是关于Django的")
        return value

(3-2)validate : 对多个字段进行比较验证时
class BookInfoSerializer(serializers.Serializer):
    def validate(self, attrs):      使用attrs
        bread = attrs['bread']
        bcomment = attrs['bcomment']
        if bread < bcomment:
            raise serializers.ValidationError('阅读量小于评论量')
        return attrs
        
(3-3)validators : 在字段中添加validators选项参数,也可以补充验证行为,这时候验证函数名随便起,   
                    但是验证哪个字段就在哪个字段加,其实就是方法(1-1),但是函数是写在class外部的,全局的
def about_django(value):
    if 'django' not in value.lower():
        raise serializers.ValidationError("图书不是关于Django的")  注意并不需要return
class BookInfoSerializer(serializers.Serializer):
    btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django]) 注意是[]
    
REST framework内置的validators :
    单字段唯一 : UniqueValidator
            validators=[UniqueValidator(queryset=BlogPost.objects.all())]
    联合唯一 : UniqueTogetherValidation     是都唯一还是有一个唯一就行
            class ExampleSerializer(serializers.Serializer):
                # 写在类中
                class Meta:
                    validators = [
                        UniqueTogetherValidator(
                            queryset=ToDoItem.objects.all(),
                            fields=('list', 'position')
                        )]
'''

'''
6-2.保存

验证成功,validated_data可以取出数据,serializer.save()保存并返回数据对象,实际是执行create()和update()方法,好像不用重写,但是讲义中有具体执行过程

说明:
serializer.save(),save中可以传参数,参数可以在create()和update()中的validated_data参数获取到
默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

针对序列化器:三个参数,第一个参数好像可以作反序列化的对象使用, 有对象且必有data参数
                    而如果是序列化第一个参数作为序列化的对象,遍历它
'''

'''
7.子类 ModelSerializer

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo        # 依据的模型类
        fields = '__all__'      # 所有字段

可以验证(shell): serializer = BookInfoSerializer()
            >>> serializer  可以看到结构

7-1.指定字段
(1) 指定 fields = ('id', 'btitle', 'bpub_date')
(2) 排除 exclude = ('image',)  注意是元组
(3) 指明只读字段 read_only_fields = ('id', 'bread', 'bcomment') 即只在序列化输出时使用

7-2.嵌套关系字段  depth
默认生成的hbook = PrimaryKeyRelatedField(label='图书', queryset=BookInfo.objects.all())就是个外键,并且以id来关联
嵌套的层级和详细信息   depth = 1
    hbook = NestedSerializer(read_only=True): 并且有所属书籍的详细信息

7-3.添加或修改原有参数
extra_kwargs = {
            'bread': {'min_value': 0, 'required': True}},
            'bcomment': {'min_value': 0, 'required': True}},
        }

修改了默认生成的序列化器中字段的参数
bread = IntegerField(label='阅读量', max_value=2147483647, min_value=0, required=True)
bcomment = IntegerField(label='评论量', max_value=2147483647, min_value=0, required=True)
'''

后续

'''
1.request和response

DRF的request是Parser解析器处理过的请求
request.data : POST,PUT,PATCH,表单,json
request.query_params : ?后边的参数

DRF的response是Renderer渲染器处理过的响应
需要在settings中加入配置:
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:字典(序列化后的数据)
常用属性:
        response.data:传给response对象的序列化后,但尚未render处理的数据
        response.status_code:状态码
        response.context:经过render处理后的响应数据
有个状态码常量模块
'''

'''
2.类视图
提供一堆类视图APIView子类,就是不断继承重新,为了使用特定的方法

2-1.APIView类:(继承于django的View)
继承问题: django是继承View,现在DRF是继承APIView,Parses解释器和Renderer渲染器对request和response对象的构建,是APIView类来实现的
特点:
    任何APIException异常都会被捕获到,并且处理成合适的响应信息;
    在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
    即可以自定义的属性: authentication_classes 列表或元祖,身份认证类
                     permissoin_classes 列表或元祖,权限检查类
                     throttle_classes 列表或元祖,流量控制类

2-2.GenericAPIView类:(继承于APIView)
增加了对于列表视图和详情视图可能用到的通用支持方法。通常使用时,可搭配一个或多个Mixin扩展类。
可以自定义的属性:
    列表视图与详情视图通用:
        queryset 列表视图的查询集
        serializer_class 视图使用的序列化器
    列表视图使用:
        pagination_class 分页控制类
        filter_backends 过滤控制后端
    详情页视图使用:
        lookup_field 查询单一数据库对象时使用的条件字段,默认为'pk'
        lookup_url_kwarg 查询单一数据时URL中的参数关键字名称,默认与look_field相同
        
可以自定义的方法:
    列表视图与详情视图通用:
        get_queryset(self)  返回视图使用的查询集
        get_serializer_class(self)  返回序列化器类
        get_serializer(self, args, *kwargs)  返回序列化器对象
    详情视图使用:
        get_object(self)  返回详情视图所需的模型类数据对象
        
# 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()    根据pk找到需要的对象
        serializer = self.get_serializer(book)  把书的对象传到序列化器中
        return Response(serializer.data)

3.扩展类:
3-1.ListModelMixin: list方法会对数据进行过滤和分页
class BookListView(ListModelMixin, GenericAPIView): 和django的Mixin扩展类继承相同
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request):
        return self.list(request)
3-2.CreateModelMixin : create方法快速实现创建资源的视图,成功返回201,数据验证失败400错误
3-3.RetrieveModelMixin : retrieve方法返回一个存在的数据对象,存在,返回200, 否则返回404
     def get(self, request, pk):
        return self.retrieve(request)
3-4.UpdateModelMixin : update方法更新一个存在的数据对象
                        partial_update局部更新, 成功返回200,序列化器校验数据失败时,返回400错误
3-5.DestroyModelMixin : destroy方法删除一个存在的数据对象,成功返回204,不存在返回404

还有几个子类视图,就是把GenericAPIView和Mixin功能写一起了,看讲义
'''

'''
3.视图集ViewSet

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

action行为:
url(r'^books/$', BookInfoViewSet.as_view('get', 'list')),       get方法获取所有书籍-> list方法
url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view('get', 'retrieve'))

常用视图集父类:
ViewSet(继承自APIView):提供了身份认证、权限校验、流量管理等
GenericViewSet(继承自GenericAPIView)
ModelViewSet(继承自GenericAPIVIew,同时包括了所有5个扩展)
ReadOnlyModelViewSet(继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin)

自定义action:
action装饰器: methods  支持的请求方式,列表传递,
            detail  action中要处理的是否是视图资源的对象(即是否通过url路径获取主键)\
                    True 表示使用通过URL获取的主键对应的数据对象
                    False 表示不使用URL获取主键

# detail为False 表示不需要处理具体的BookInfo对象 
@action(methods=['get'], detail=False)
def latest(self, request):
    """
    返回最新的图书信息
    """
    book = BookInfo.objects.latest('id')
    serializer = self.get_serializer(book)
    return Response(serializer.data)
        
# detail为True,表示要处理具体与pk主键对应的BookInfo对象
@action(methods=['put'], detail=True)
def read(self, request, pk):
    """
    修改图书的阅读量数据
    """
    book = self.get_object()
    book.bread = request.data.get('read')
    book.save()
    serializer = self.get_serializer(book)
    return Response(serializer.data)  
    
url(r'^books/latest/$', views.BookInfoViewSet.as_view({'get': 'latest'})),
url(r'^books/(?P<pk>\d+)/read/$', views.BookInfoViewSet.as_view({'put': 'read'})),
       
'''

参考链接:https://blog.csdn.net/sunsady/article/details/80450520

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: DRF(Django Rest Framework)框架可以让你自定义错误处理。你可以定义一个自定义异常类来处理特定的错误,并在视图中抛出该异常。然后,在配置的异常处理器中对该异常进行处理。你也可以重写DRF的默认异常处理器来处理所有错误。 ### 回答2: 在DRF框架中,我们可以通过自定义错误处理来提供更加友好和详细的错误提示信息。自定义错误处理可以帮助我们在API开发过程中能够迅速定位和解决问题,提高开发效率。 首先,我们可以通过重写DRF中的异常处理器来自定义错误响应。通过继承`exception_handler`方法,我们可以在该方法中检查不同的异常类型,并返回相应的错误响应。可以处理的异常类型包括`APIException`、`PermissionDenied`、`AuthenticationFailed`等。 在自定义错误响应中,我们可以设置不同的错误码、错误信息和HTTP状态码,以确保错误响应符合我们的需求。例如,我们可以根据不同的异常返回不同的错误码以及对应的错误信息,可以参考HTTP状态码的规范来制定自己的错误码。 除了自定义错误响应外,我们还可以对DRF中的验证器进行自定义。通过继承DRF中的验证器类,我们可以自定义各种验证规则,以满足不同的业务需求。在自定义验证器中,我们可以通过重写验证方法来实现特定的验证逻辑。 另外,我们还可以自定义错误处理的日志记录。通过重写`handle_exception`方法,我们可以在捕获异常时,将异常的相关信息记录到日志中,便于后续排查问题。在日志记录中,我们可以输出异常的类型、错误信息、请求参数等,以便于定位问题所在。 总之,通过DRF框架的自定义错误处理功能,我们可以灵活地定制错误响应、验证规则和日志记录等,提高API开发的可维护性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值