前言
我的 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 对象,文件属性默认有绝对路径而不是相对路径的原因了~
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对小牛知识库的支持。
windows系统中,如何给文件夹添加完整性校验并写入属性中?
新的节点红色,只是第一次尝试这个节点。 我希望将时间戳用作文件名,但似乎无法弄清楚如何使AWS节点将属性用作文件名。 根据文件“Amazon S3 out节点。将内容上载到Amazon S3 bucket。bucket名称可以在node bucket属性或msg.bucket属性中指定。Amazon S3上的文件名取自node filename属性或msg.filename属性。内容取自node属
在时间并不重要的地方,比如在备份程序中,文件完整性是唯一需要的,有人会反对MD5来采用不同的算法,甚至建议采用不同的技术吗? 使用MD5会产生校验和吗?
问题内容: 不返回pattern作为列表的元素之一。即它返回: 根据手册,它应该包含 对象的属性名称,其类的属性名称,以及递归其类的基类的属性。 它也说 该列表不一定完整。 有没有办法获得 完整的 清单?我一直以为dir返回一个完整的列表,但显然并没有… 另外:有没有办法只列出属性?还是只有方法? 编辑:这实际上是python中的错误- >据称它已在3.0分支中修复(也许在2.6中已修复) 问题答
问题内容: 这个问题已经在这里有了答案 : 7年前关闭。 可能重复: 使用jQuery输入文件的完整路径 我有以下html元素 如果我用 我只是文件名,而不是文件的完整绝对路径。有人可以告诉我如何获得完整路径吗? 问题答案: 您不能这样做-由于安全问题,浏览器将不允许这样做。尽管有解决方法,但事实是您不应该依靠这种方法。以下堆栈溢出问题与此处相关: 使用jquery输入文件的完整路径 如何从Fir
主要内容:什么是文件?,文件的属性什么是文件? 文件可以定义为一个存储记录序列的数据结构。 文件存储在文件系统中,该文件系统可能存在于磁盘或主存储器中。 文件可以是简单的(纯文本)或复杂的(特殊格式)。 文件的集合被称为目录。 在不同级别的目录集合被称为文件系统。 文件的属性 常见的文件属性如下所示 编号 属性 描述 1 名称 每个文件都包含文件在文件系统中被识别的名称。 同一目录中不能有两个同名的文件。 2 标识符 每个文件都有