Django REST为文件属性输出完整URL的方法


Posted in Python onDecember 18, 2017

前言

我的 App 项目的 API 部分是使用 Django REST Framework 来搭建的,它可以像搭积木一样非常方便地搭出 API,兼具方便和灵活。

django是一个神奇的框架,而restframework又是遵循了这个框架的另一个神奇的框架,然而由于restframework的文档稀烂无比,很多时候你必须看源码才能写出科学的代码,这挡住了很多新手的路。

在使用的过程中我也积累了一些小技巧,这里写一则关于如何为文件属性输出完整 URL 的字段。

实现方法

一个典型的案例是,当请求 /profile/ 这个 API 的时候,返回类似于这样的结果:

{
 "id": 1,
 "nickname": "管理员",
 "mobilephone": "1234567890",
 "avatar": "/media/profiles/2017/12/17/avatar.png"
}

在 Django REST 的定义中,我使用了自定义的一个扩展自 rest_framework.views.APIView 的 ProfileView 类型,实现了它的 get 方法,来给认证的用户返回一个 Profile 对象:

class ProfileView(APIView):
 def get(self, request):
  user = request.user
  if user.is_authenticated:
   profile = Profile.objects.get(user=user)
   return Response(ProfileSerializer(profile).data)
  else:
   raise exceptions.AuthenticationFailed('Not authenticated user!')

这里的逻辑很简单,判断请求当前 API 的用户是不是已经验证过的用户,如果是的话,再得到它的 Profile,再通过 ProfileSerializer 把 profile 实例序列化成 JSON 对象。如果不是已验证用户,则会返回 401 验证失败相关信息。

以上输出的内容,交给 Web 前端使用是没什么问题的,但如果是给 App 使用,那么 avatar 这个文件属性的相对 URL 不太合适,于是我们要改造一下这个 API,使其能输出绝对 URL。

如何做呢?只需要将上面的 get 方法,稍加修改即可:

-class ProfileView(APIView):
+class ProfileView(generics.GenericAPIView):
  parser_classes = (MultiPartParser, FormParser)
+ serializer_class = ProfileSerializer
  def get(self, request):
   user = request.user
   if user.is_authenticated:
    profile = Profile.objects.get(user=user)
-   return Response(ProfileSerializer(profile).data)
+   serializer = self.get_serializer(profile)
+   return Response(serializer.data)
   else:
    raise exceptions.AuthenticationFailed('Not authenticated user!')

不同于之前继承自 APIView,现在继承自 generics.GenericAPIView,这是一个更通用的类,可以看到,这里通过手动构建 ProfileSerializer 改成通过 self.get_serializer 来进行,这里有什么不同呢?

还得看看 Django REST 的源码,GenericAPIView 这个类的 get_serializer 在做什么。

def get_serializer(self, *args, **kwargs):
    """
    Return the serializer instance that should be used for validating and
    deserializing input, and for serializing output.
    """
    serializer_class = self.get_serializer_class()
    kwargs['context'] = self.get_serializer_context()
    return serializer_class(*args, **kwargs)

可以看到,这个方法在创建 serializer 的时候,会把 context 传进去,而 get_serializer_context 也是一个固定方法,它会把 request、view 和 format 这些信息包含在里面。

那么 request、view 和 format 这些信息,是如何用在 serializer 里面,最后把一个文件对象的全路径展开的呢?

省略中间 serializer 一系列序列化过程,当它遇到 FileField 的时候,会通过判断 context 里面有没有 reuqest,有的话,就调用 request.build_absolute_uri(url) 方法,把绝对地址 build 出来,而不是默认存在数据库里的相对地址。

def to_representation(self, value):
  if not value:
   return None
  use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL)
  if use_url:
   if not getattr(value, 'url', None):
    # If the file has not been saved it may not have a URL.
    return None
   url = value.url
   request = self.context.get('request', None)
   if request is not None:
    return request.build_absolute_uri(url)
   return url
  return value.name

这就是为什么通过 GenericAPIView 来输出 API 对象,文件属性默认有绝对路径而不是相对路径的原因了~

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python中的文件和目录操作实现代码
Mar 13 Python
python实现多线程网页下载器
Apr 15 Python
python读取视频流提取视频帧的两种方法
Oct 22 Python
Python 中的range(),以及列表切片方法
Jul 02 Python
浅谈python 导入模块和解决文件句柄找不到问题
Dec 15 Python
python机器学习库scikit-learn:SVR的基本应用
Jun 26 Python
Python利用神经网络解决非线性回归问题实例详解
Jul 19 Python
详解Python Matplotlib解决绘图X轴值不按数组排序问题
Aug 05 Python
Python3连接Mysql8.0遇到的问题及处理步骤
Feb 17 Python
Django Admin设置应用程序及模型顺序方法详解
Apr 01 Python
如何用python 操作zookeeper
Dec 28 Python
python中@contextmanager实例用法
Feb 07 Python
Python3计算三角形的面积代码
Dec 18 #Python
利用python解决mysql视图导入导出依赖的问题
Dec 17 #Python
python 3.5实现检测路由器流量并写入txt的方法实例
Dec 17 #Python
python中闭包Closure函数作为返回值的方法示例
Dec 17 #Python
django模板语法学习之include示例详解
Dec 17 #Python
详解python string类型 bytes类型 bytearray类型
Dec 16 #Python
python使用os.listdir和os.walk获得文件的路径的方法
Dec 16 #Python
You might like
php 字符串替换的方法
2012/01/10 PHP
PHP单例模式详细介绍
2015/07/01 PHP
thinkphp框架表单数组实现图片批量上传功能示例
2020/04/04 PHP
Yii 框架使用数据库(databases)的方法示例
2020/05/19 PHP
thinkphp诸多限制条件下如何getshell详解
2020/12/09 PHP
jquery插件制作教程 txtHover
2012/08/17 Javascript
打印json对象的内容及JSON.stringify函数应用
2013/03/29 Javascript
使用JS读秒使用示例
2013/09/21 Javascript
JS实现日期加减的方法
2013/11/29 Javascript
jquery提示效果实例分析
2014/11/25 Javascript
IE7浏览器窗口大小改变事件执行多次bug及IE6/IE7/IE8下resize问题
2015/08/21 Javascript
JS实现的左侧竖向滑动菜单效果代码
2015/10/19 Javascript
常见JS验证脚本汇总
2015/12/01 Javascript
初识angular框架后的所思所想
2016/02/19 Javascript
jQuery-mobile事件监听与用法详解
2016/11/23 Javascript
最全正则表达式总结:验证QQ号、手机号、Email、中文、邮编、身份证、IP地址等
2017/08/16 Javascript
Vue的Class与Style绑定的方法
2017/09/01 Javascript
JavaScript面向对象精要(上部)
2017/09/12 Javascript
vue中$set的使用(结合在实际应用中遇到的坑)
2018/07/10 Javascript
JS实现的简单分页功能示例
2018/08/23 Javascript
laravel-admin 与 vue 结合使用实例代码详解
2019/06/04 Javascript
对numpy.append()里的axis的用法详解
2018/06/28 Python
python sleep和wait对比总结
2021/02/03 Python
美国电视购物HSN官网:HSN
2016/09/07 全球购物
专门经营化妆刷的美国彩妆品牌:Sigma Beauty
2017/09/11 全球购物
芬兰设计商店美国:Finnish Design Shop US
2019/03/25 全球购物
KELLER SPORTS荷兰:在线订购最好的运动产品
2020/10/13 全球购物
Vuori官网:运动服装的终级表现
2021/01/27 全球购物
私有程序集与共享程序集有什么区别
2013/04/05 面试题
Linux文件操作命令都有哪些
2015/02/27 面试题
初中生自我鉴定
2014/02/04 职场文书
教师自我鉴定范文
2014/03/20 职场文书
招标承诺书
2014/08/30 职场文书
2015年会计年终工作总结
2015/05/26 职场文书
班干部竞选演讲稿(精选5篇)
2019/09/24 职场文书
Nginx如何配置多个服务域名解析共用80端口详解
2022/09/23 Servers