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实现堆栈与队列的方法
Jan 15 Python
探究python中open函数的使用
Mar 01 Python
教你用一行Python代码实现并行任务(附代码)
Feb 02 Python
python负载均衡的简单实现方法
Feb 04 Python
浅谈tensorflow中几个随机函数的用法
Jul 27 Python
python常用函数与用法示例
Jul 02 Python
Python 中的 global 标识对变量作用域的影响
Aug 12 Python
Python中关于浮点数的冷知识
Sep 22 Python
python实现的按要求生成手机号功能示例
Oct 08 Python
Python使用循环神经网络解决文本分类问题的方法详解
Jan 16 Python
tensorflow 利用expand_dims和squeeze扩展和压缩tensor维度方式
Feb 07 Python
Python如何快速找到多个字典中的公共键(key)
Apr 29 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 仿Comsenz安装效果代码打包提供下载
2010/05/09 PHP
php多任务程序实例解析
2014/07/19 PHP
php表单提交与$_POST实例分析
2015/01/26 PHP
php模式设计之观察者模式应用实例分析
2019/09/25 PHP
firefox 和 ie 事件处理的细节,研究,再研究 书写同时兼容ie和ff的事件处理代码
2007/04/12 Javascript
不同浏览器对回车提交表单的处理办法
2010/02/13 Javascript
Tab页界面 用jQuery及Ajax技术实现(php后台)
2011/10/12 Javascript
jquery 插件学习(四)
2012/08/06 Javascript
js获取单选框或复选框值及操作
2012/12/18 Javascript
深入解析JavaScript的闭包机制
2015/10/20 Javascript
JavaScript事件类型中焦点、鼠标和滚轮事件详解
2016/01/25 Javascript
Bootstrap打造一个左侧折叠菜单的系统模板(一)
2016/05/17 Javascript
详解JavaScript按概率随机生成事件
2017/08/02 Javascript
async/await地狱该如何避免详解
2018/05/10 Javascript
浅谈Javascript中的对象和继承
2019/04/19 Javascript
JS实现横向轮播图(初级版)
2020/06/24 Javascript
Postman环境变量全局变量使用方法详解
2020/08/13 Javascript
[42:23]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第二场 12.10
2020/12/13 DOTA
[08:06]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Elephant 选手采访
2021/03/11 DOTA
[57:31]DOTA2-DPC中国联赛 正赛 SAG vs CDEC BO3 第一场 2月1日
2021/03/11 DOTA
Python的Django框架中URLconf相关的一些技巧整理
2015/07/18 Python
python装饰器初探(推荐)
2016/07/21 Python
Python之日期与时间处理模块(date和datetime)
2017/02/16 Python
Python批量更改文件名的实现方法
2017/10/29 Python
对Python使用mfcc的两种方式详解
2019/01/09 Python
Python数据可视化教程之Matplotlib实现各种图表实例
2019/01/13 Python
Python设计模式之模板方法模式实例详解
2019/01/17 Python
Python实现FTP弱口令扫描器的方法示例
2019/01/31 Python
python3+PyQt5 自定义窗口部件--使用窗口部件样式表的方法
2019/06/26 Python
Python爬虫之urllib基础用法教程
2019/10/12 Python
python简单的三元一次方程求解实例
2020/04/02 Python
Python里面如何实现tuple和list的转换
2012/06/13 面试题
外贸公司实习自我鉴定
2013/09/24 职场文书
行政管理人员精品工作推荐信
2013/11/04 职场文书
2016大学生诚信考试承诺书
2016/03/25 职场文书
Win10多屏显示如何设置?Win10电脑多屏显示设置操作方法
2022/07/07 数码科技