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使用urllib模块开发的多线程豆瓣小站mp3下载器
Jan 16 Python
python进阶教程之异常处理
Aug 30 Python
常见的在Python中实现单例模式的三种方法
Apr 08 Python
Python中使用hashlib模块处理算法的教程
Apr 28 Python
python比较两个列表是否相等的方法
Jul 28 Python
一个基于flask的web应用诞生 bootstrap框架美化(3)
Apr 11 Python
python3爬虫之设计签名小程序
Jun 19 Python
元组列表字典(莫烦python基础)
Apr 03 Python
PyCharm 创建指定版本的 Django(超详图解教程)
Jun 18 Python
通过Python编写一个简单登录功能过程解析
Sep 04 Python
pandas按行按列遍历Dataframe的几种方式
Oct 23 Python
python爬虫看看虎牙女主播中谁最“顶”步骤详解
Dec 01 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实现的一个简单json rpc框架实例
2015/03/30 PHP
微信支付PHP SDK之微信公众号支付代码详解
2015/12/09 PHP
修改WordPress中文章编辑器的样式的方法详解
2015/12/15 PHP
让innerHTML的脚本也可以运行起来
2006/07/01 Javascript
使用JavaScript构建JSON格式字符串实现步骤
2013/03/22 Javascript
Javascript 修改String 对象 增加去除空格功能(示例代码)
2013/11/30 Javascript
javascript中使用未定义变量或值的情况分析
2016/07/19 Javascript
Angular2 Service实现简单音乐播放器服务
2017/02/24 Javascript
解析jquery easyui tree异步加载子节点问题
2017/03/08 Javascript
vue2.0的contextmenu右键弹出菜单的实例代码
2017/07/24 Javascript
详解React项目的服务端渲染改造(koa2+webpack3.11)
2018/03/19 Javascript
通过npm或yarn自动生成vue组件的方法示例
2019/02/12 Javascript
jQuery实现B2B网站后台管理系统侧导航
2020/07/08 jQuery
微信小程序实现聊天室
2020/08/21 Javascript
聊聊vue 中的v-on参数问题
2021/01/29 Vue.js
把MySQL表结构映射为Python中的对象的教程
2015/04/07 Python
浅谈python内置变量-reversed(seq)
2017/06/21 Python
详解Golang 与python中的字符串反转
2017/07/21 Python
python 读写中文json的实例详解
2017/10/29 Python
python bmp转换为jpg 并删除原图的方法
2018/10/25 Python
python3.5 cv2 获取视频特定帧生成jpg图片
2019/08/28 Python
Python 50行爬虫抓取并处理图灵书目过程详解
2019/09/20 Python
pandas按行按列遍历Dataframe的几种方式
2019/10/23 Python
Python代码块及缓存机制原理详解
2019/12/13 Python
Python for循环通过序列索引迭代过程解析
2020/02/07 Python
python复合条件下的字典排序
2020/12/18 Python
解决tensorflow模型压缩的问题_踩坑无数,总算搞定
2021/03/02 Python
Gap英国官网:Gap UK
2018/07/18 全球购物
乌克兰第一的珠宝网上商店:Gold.ua
2019/11/29 全球购物
机械专业应届生求职信
2013/09/21 职场文书
技校教师求职简历的自我评价
2013/10/20 职场文书
通信工程专业毕业生推荐信
2013/12/25 职场文书
2013年研究生毕业感言
2014/02/06 职场文书
相亲活动方案
2014/08/26 职场文书
《思路决定出路》读后感3篇
2019/12/11 职场文书
Python开发五子棋小游戏
2022/04/28 Python