Django REST為文件屬性輸出完整URL的方法
前言
我的 App 項目的 API 部分是使用 Django REST Framework 來搭建的,它可以像搭積木一樣非常方便地搭出 API,兼具方便和靈活。
django是一個神奇的框架,而restframework又是遵循了這個框架的另一個神奇的框架,然而由于restframework的文檔稀爛無比,很多時候你必須看源碼才能寫出科學的代碼,這擋住了很多新手的路。
在使用的過程中我也積累了一些小技巧,這里寫一則關于如何為文件屬性輸出完整 URL 的字段。
實現(xiàn)方法
一個典型的案例是,當請求 /profile/ 這個 API 的時候,返回類似于這樣的結(jié)果:
{ "id": 1, "nickname": "管理員", "mobilephone": "1234567890", "avatar": "/media/profiles/2017/12/17/avatar.png" }
在 Django REST 的定義中,我使用了自定義的一個擴展自 rest_framework.views.APIView 的 ProfileView 類型,實現(xiàn)了它的 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 的用戶是不是已經(jīng)驗證過的用戶,如果是的話,再得到它的 Profile,再通過 ProfileSerializer 把 profile 實例序列化成 JSON 對象。如果不是已驗證用戶,則會返回 401 驗證失敗相關信息。
以上輸出的內(nèi)容,交給 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,現(xiàn)在繼承自 generics.GenericAPIView,這是一個更通用的類,可以看到,這里通過手動構(gòu)建 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)
可以看到,這個方法在創(chuàng)建 serializer 的時候,會把 context 傳進去,而 get_serializer_context 也是一個固定方法,它會把 request、view 和 format 這些信息包含在里面。
那么 request、view 和 format 這些信息,是如何用在 serializer 里面,最后把一個文件對象的全路徑展開的呢?
省略中間 serializer 一系列序列化過程,當它遇到 FileField 的時候,會通過判斷 context 里面有沒有 reuqest,有的話,就調(diào)用 request.build_absolute_uri(url) 方法,把絕對地址 build 出來,而不是默認存在數(shù)據(jù)庫里的相對地址。
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 對象,文件屬性默認有絕對路徑而不是相對路徑的原因了~
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
python基礎教程之基本數(shù)據(jù)類型和變量聲明介紹
這篇文章主要介紹了python基礎教程之基本數(shù)據(jù)類型和變量聲明介紹,首先講解了變量聲明的一些知識,然后列出最常用的基本數(shù)據(jù)類型,需要的朋友可以參考下2014-08-08Python讀取sqlite數(shù)據(jù)庫文件的方法分析
這篇文章主要介紹了Python讀取sqlite數(shù)據(jù)庫文件的方法,結(jié)合實例形式分析了Python引入sqlite3模塊操作sqlite數(shù)據(jù)庫的讀取、SQL命令執(zhí)行等相關操作技巧,需要的朋友可以參考下2017-08-08python生成每日報表數(shù)據(jù)(Excel)并郵件發(fā)送的實例
今天小編就為大家分享一篇python生成每日報表數(shù)據(jù)(Excel)并郵件發(fā)送的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-02-02Python中flatten( )函數(shù)及函數(shù)用法詳解
flatten是numpy.ndarray.flatten的一個函數(shù),即返回一個一維數(shù)組。這篇文章主要介紹了Python中flatten( )函數(shù),需要的朋友可以參考下2018-11-11