Django REST為文件屬性輸出完整URL的方法
前言
我的 App 項(xiàng)目的 API 部分是使用 Django REST Framework 來(lái)搭建的,它可以像搭積木一樣非常方便地搭出 API,兼具方便和靈活。
django是一個(gè)神奇的框架,而restframework又是遵循了這個(gè)框架的另一個(gè)神奇的框架,然而由于restframework的文檔稀爛無(wú)比,很多時(shí)候你必須看源碼才能寫(xiě)出科學(xué)的代碼,這擋住了很多新手的路。
在使用的過(guò)程中我也積累了一些小技巧,這里寫(xiě)一則關(guān)于如何為文件屬性輸出完整 URL 的字段。
實(shí)現(xiàn)方法
一個(gè)典型的案例是,當(dāng)請(qǐng)求 /profile/ 這個(gè) API 的時(shí)候,返回類似于這樣的結(jié)果:
{
"id": 1,
"nickname": "管理員",
"mobilephone": "1234567890",
"avatar": "/media/profiles/2017/12/17/avatar.png"
}
在 Django REST 的定義中,我使用了自定義的一個(gè)擴(kuò)展自 rest_framework.views.APIView 的 ProfileView 類型,實(shí)現(xiàn)了它的 get 方法,來(lái)給認(rèn)證的用戶返回一個(gè) Profile 對(duì)象:
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!')
這里的邏輯很簡(jiǎn)單,判斷請(qǐng)求當(dāng)前 API 的用戶是不是已經(jīng)驗(yàn)證過(guò)的用戶,如果是的話,再得到它的 Profile,再通過(guò) ProfileSerializer 把 profile 實(shí)例序列化成 JSON 對(duì)象。如果不是已驗(yàn)證用戶,則會(huì)返回 401 驗(yàn)證失敗相關(guān)信息。
以上輸出的內(nèi)容,交給 Web 前端使用是沒(méi)什么問(wèn)題的,但如果是給 App 使用,那么 avatar 這個(gè)文件屬性的相對(duì) URL 不太合適,于是我們要改造一下這個(gè) API,使其能輸出絕對(duì) 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è)更通用的類,可以看到,這里通過(guò)手動(dòng)構(gòu)建 ProfileSerializer 改成通過(guò) self.get_serializer 來(lái)進(jìn)行,這里有什么不同呢?
還得看看 Django REST 的源碼,GenericAPIView 這個(gè)類的 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)
可以看到,這個(gè)方法在創(chuàng)建 serializer 的時(shí)候,會(huì)把 context 傳進(jìn)去,而 get_serializer_context 也是一個(gè)固定方法,它會(huì)把 request、view 和 format 這些信息包含在里面。
那么 request、view 和 format 這些信息,是如何用在 serializer 里面,最后把一個(gè)文件對(duì)象的全路徑展開(kāi)的呢?
省略中間 serializer 一系列序列化過(guò)程,當(dāng)它遇到 FileField 的時(shí)候,會(huì)通過(guò)判斷 context 里面有沒(méi)有 reuqest,有的話,就調(diào)用 request.build_absolute_uri(url) 方法,把絕對(duì)地址 build 出來(lái),而不是默認(rèn)存在數(shù)據(jù)庫(kù)里的相對(duì)地址。
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
這就是為什么通過(guò) GenericAPIView 來(lái)輸出 API 對(duì)象,文件屬性默認(rèn)有絕對(duì)路徑而不是相對(duì)路徑的原因了~
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
python 尋找list中最大元素對(duì)應(yīng)的索引方法
今天小編就為大家分享一篇python 尋找list中最大元素對(duì)應(yīng)的索引方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
Matlab中如何實(shí)現(xiàn)將長(zhǎng)字符串換行寫(xiě)
這篇文章主要介紹了Matlab中如何實(shí)現(xiàn)將長(zhǎng)字符串換行寫(xiě)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
python實(shí)現(xiàn)百度關(guān)鍵詞排名查詢
這篇文章主要介紹了python實(shí)現(xiàn)百度關(guān)鍵詞排名查詢,需要的朋友可以參考下2014-03-03
Pycharm IDE安裝環(huán)境配置的2025最新完整版教程
PyCharm是目前最流行、使用最廣泛的Python IDE,帶有一整套可以幫助用戶在使用Python語(yǔ)言開(kāi)發(fā)時(shí)提高其效率的工具,下面我們來(lái)看看Pycharm IDE安裝環(huán)境配置的最新教程吧2025-03-03
python+logging+yaml實(shí)現(xiàn)日志分割
這篇文章主要為大家詳細(xì)介紹了python+logging+yaml實(shí)現(xiàn)日志分割,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
詳細(xì)總結(jié)Python類的多繼承知識(shí)
Python類的多繼承知識(shí)是非常易于新手理解的,如果你是剛剛?cè)腴TPython的話,歡迎參考本篇文章,本文對(duì)Python類的多繼承知識(shí)作出了非常詳細(xì)的解釋,還有相關(guān)代碼參考哦。2021-05-05
Python 實(shí)現(xiàn)某個(gè)功能每隔一段時(shí)間被執(zhí)行一次的功能方法
今天小編就為大家分享一篇Python 實(shí)現(xiàn)某個(gè)功能每隔一段時(shí)間被執(zhí)行一次的功能方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10

